mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 06:21:40 +00:00
WIP reimplement material psets with new features. See #1222.
* Data type sensitive UI * New standardised UI * Accomodate custom pset templates for materials * Explicitly disable IFC2X3 material psets which are horrible and I don't want to support it
This commit is contained in:
@@ -6,8 +6,6 @@ def draw_ui(context, layout, obj_type):
|
|||||||
obj = context.active_object if obj_type == "Object" else context.active_object.active_material
|
obj = context.active_object if obj_type == "Object" else context.active_object.active_material
|
||||||
oprops = obj.BIMObjectProperties
|
oprops = obj.BIMObjectProperties
|
||||||
props = obj.BIMAttributeProperties
|
props = obj.BIMAttributeProperties
|
||||||
if not oprops.ifc_definition_id:
|
|
||||||
return
|
|
||||||
if oprops.ifc_definition_id not in Data.products:
|
if oprops.ifc_definition_id not in Data.products:
|
||||||
Data.load(oprops.ifc_definition_id)
|
Data.load(oprops.ifc_definition_id)
|
||||||
|
|
||||||
@@ -88,7 +86,10 @@ class BIM_PT_material_attributes(Panel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id)
|
try:
|
||||||
|
return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
draw_ui(context, self.layout, "Material")
|
draw_ui(context, self.layout, "Material")
|
||||||
|
|||||||
@@ -13,12 +13,15 @@ classes = (
|
|||||||
prop.PsetProperties,
|
prop.PsetProperties,
|
||||||
ui.BIM_PT_object_psets,
|
ui.BIM_PT_object_psets,
|
||||||
ui.BIM_PT_object_qtos,
|
ui.BIM_PT_object_qtos,
|
||||||
|
ui.BIM_PT_material_psets,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.types.Object.PsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties)
|
bpy.types.Object.PsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties)
|
||||||
|
bpy.types.Material.PsetProperties = bpy.props.PointerProperty(type=prop.PsetProperties)
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
del bpy.types.Object.PsetProperties
|
del bpy.types.Object.PsetProperties
|
||||||
|
del bpy.types.Material.PsetProperties
|
||||||
|
|||||||
@@ -32,9 +32,8 @@ class Usecase:
|
|||||||
self.settings["product"].HasPropertySets = has_property_sets
|
self.settings["product"].HasPropertySets = has_property_sets
|
||||||
elif self.settings["product"].is_a("IfcMaterialDefinition"):
|
elif self.settings["product"].is_a("IfcMaterialDefinition"):
|
||||||
pset = self.file.create_entity(
|
pset = self.file.create_entity(
|
||||||
"IfcPropertySet",
|
"IfcMaterialProperties",
|
||||||
**{
|
**{
|
||||||
"GlobalId": ifcopenshell.guid.new(),
|
|
||||||
"Name": self.settings["Name"],
|
"Name": self.settings["Name"],
|
||||||
"Material": self.settings["product"],
|
"Material": self.settings["product"],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ class Data:
|
|||||||
cls.products[product_id] = {"psets": set(), "qtos": set()}
|
cls.products[product_id] = {"psets": set(), "qtos": set()}
|
||||||
if product.is_a("IfcElementType"):
|
if product.is_a("IfcElementType"):
|
||||||
cls.add_type_product_psets(product, product_id)
|
cls.add_type_product_psets(product, product_id)
|
||||||
|
elif product.is_a("IfcMaterialDefinition"):
|
||||||
|
cls.add_material_psets(product, product_id)
|
||||||
else:
|
else:
|
||||||
cls.add_product_psets(product, product_id)
|
cls.add_product_psets(product, product_id)
|
||||||
|
|
||||||
@@ -28,6 +30,13 @@ class Data:
|
|||||||
if definition.is_a("IfcPropertySet"):
|
if definition.is_a("IfcPropertySet"):
|
||||||
cls.add_pset(definition, product_id)
|
cls.add_pset(definition, product_id)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_material_psets(cls, product, product_id):
|
||||||
|
if not product.HasProperties:
|
||||||
|
return
|
||||||
|
for pset in product.HasProperties:
|
||||||
|
cls.add_pset(pset, product_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_product_psets(cls, product, product_id):
|
def add_product_psets(cls, product, product_id):
|
||||||
if not hasattr(product, "IsDefinedBy") or not product.IsDefinedBy:
|
if not hasattr(product, "IsDefinedBy") or not product.IsDefinedBy:
|
||||||
|
|||||||
@@ -27,9 +27,14 @@ class EnablePsetEditing(bpy.types.Operator):
|
|||||||
bl_idname = "bim.enable_pset_editing"
|
bl_idname = "bim.enable_pset_editing"
|
||||||
bl_label = "Enable Pset Editing"
|
bl_label = "Enable Pset Editing"
|
||||||
pset_id: bpy.props.IntProperty()
|
pset_id: bpy.props.IntProperty()
|
||||||
|
obj: bpy.props.StringProperty()
|
||||||
|
obj_type: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = bpy.context.active_object
|
if self.obj_type == "Object":
|
||||||
|
obj = bpy.data.objects.get(self.obj)
|
||||||
|
elif self.obj_type == "Material":
|
||||||
|
obj = bpy.data.materials.get(self.obj)
|
||||||
props = obj.PsetProperties
|
props = obj.PsetProperties
|
||||||
|
|
||||||
while len(props.properties) > 0:
|
while len(props.properties) > 0:
|
||||||
@@ -61,9 +66,14 @@ class EnablePsetEditing(bpy.types.Operator):
|
|||||||
class DisablePsetEditing(bpy.types.Operator):
|
class DisablePsetEditing(bpy.types.Operator):
|
||||||
bl_idname = "bim.disable_pset_editing"
|
bl_idname = "bim.disable_pset_editing"
|
||||||
bl_label = "Disable Pset Editing"
|
bl_label = "Disable Pset Editing"
|
||||||
|
obj: bpy.props.StringProperty()
|
||||||
|
obj_type: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
obj = bpy.context.active_object
|
if self.obj_type == "Object":
|
||||||
|
obj = bpy.data.objects.get(self.obj)
|
||||||
|
elif self.obj_type == "Material":
|
||||||
|
obj = bpy.data.materials.get(self.obj)
|
||||||
props = obj.PsetProperties
|
props = obj.PsetProperties
|
||||||
props.active_pset_id = 0
|
props.active_pset_id = 0
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -72,10 +82,15 @@ class DisablePsetEditing(bpy.types.Operator):
|
|||||||
class EditPset(bpy.types.Operator):
|
class EditPset(bpy.types.Operator):
|
||||||
bl_idname = "bim.edit_pset"
|
bl_idname = "bim.edit_pset"
|
||||||
bl_label = "Edit Pset"
|
bl_label = "Edit Pset"
|
||||||
|
obj: bpy.props.StringProperty()
|
||||||
|
obj_type: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
obj = bpy.context.active_object
|
if self.obj_type == "Object":
|
||||||
|
obj = bpy.data.objects.get(self.obj)
|
||||||
|
elif self.obj_type == "Material":
|
||||||
|
obj = bpy.data.materials.get(self.obj)
|
||||||
oprops = obj.BIMObjectProperties
|
oprops = obj.BIMObjectProperties
|
||||||
props = obj.PsetProperties
|
props = obj.PsetProperties
|
||||||
properties = {}
|
properties = {}
|
||||||
@@ -109,7 +124,7 @@ class EditPset(bpy.types.Operator):
|
|||||||
"Properties": properties
|
"Properties": properties
|
||||||
}).execute()
|
}).execute()
|
||||||
Data.load(oprops.ifc_definition_id)
|
Data.load(oprops.ifc_definition_id)
|
||||||
bpy.ops.bim.disable_pset_editing()
|
bpy.ops.bim.disable_pset_editing(obj=self.obj, obj_type=self.obj_type)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -117,10 +132,15 @@ class RemovePset(bpy.types.Operator):
|
|||||||
bl_idname = "bim.remove_pset"
|
bl_idname = "bim.remove_pset"
|
||||||
bl_label = "Remove Pset"
|
bl_label = "Remove Pset"
|
||||||
pset_id: bpy.props.IntProperty()
|
pset_id: bpy.props.IntProperty()
|
||||||
|
obj: bpy.props.StringProperty()
|
||||||
|
obj_type: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
obj = bpy.context.active_object
|
if self.obj_type == "Object":
|
||||||
|
obj = bpy.data.objects.get(self.obj)
|
||||||
|
elif self.obj_type == "Material":
|
||||||
|
obj = bpy.data.materials.get(self.obj)
|
||||||
props = obj.BIMObjectProperties
|
props = obj.BIMObjectProperties
|
||||||
remove_pset.Usecase(self.file, {
|
remove_pset.Usecase(self.file, {
|
||||||
"product": self.file.by_id(props.ifc_definition_id),
|
"product": self.file.by_id(props.ifc_definition_id),
|
||||||
@@ -133,15 +153,20 @@ class RemovePset(bpy.types.Operator):
|
|||||||
class AddPset(bpy.types.Operator):
|
class AddPset(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_pset"
|
bl_idname = "bim.add_pset"
|
||||||
bl_label = "Add Pset"
|
bl_label = "Add Pset"
|
||||||
|
obj: bpy.props.StringProperty()
|
||||||
|
obj_type: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
obj = bpy.context.active_object
|
if self.obj_type == "Object":
|
||||||
|
obj = bpy.data.objects.get(self.obj)
|
||||||
|
elif self.obj_type == "Material":
|
||||||
|
obj = bpy.data.materials.get(self.obj)
|
||||||
oprops = obj.BIMObjectProperties
|
oprops = obj.BIMObjectProperties
|
||||||
props = obj.PsetProperties
|
props = obj.PsetProperties
|
||||||
add_pset.Usecase(self.file, {
|
add_pset.Usecase(self.file, {
|
||||||
"product": self.file.by_id(oprops.ifc_definition_id),
|
"product": self.file.by_id(oprops.ifc_definition_id),
|
||||||
"Name": props.pset_name,
|
"Name": props.pset_name if self.obj_type == "Object" else props.material_pset_name,
|
||||||
}).execute()
|
}).execute()
|
||||||
Data.load(oprops.ifc_definition_id)
|
Data.load(oprops.ifc_definition_id)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -29,6 +29,17 @@ def getPsetNames(self, context):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def getMaterialPsetNames(self, context):
|
||||||
|
global psetnames
|
||||||
|
if "/" in context.active_object.name:
|
||||||
|
ifc_class = "IfcMaterial"
|
||||||
|
if ifc_class not in psetnames:
|
||||||
|
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
|
||||||
|
psetnames[ifc_class] = [(p.Name, p.Name, "") for p in psets]
|
||||||
|
return psetnames[ifc_class]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def getQtoNames(self, context):
|
def getQtoNames(self, context):
|
||||||
global qtonames
|
global qtonames
|
||||||
if "/" in context.active_object.name:
|
if "/" in context.active_object.name:
|
||||||
@@ -46,3 +57,4 @@ class PsetProperties(PropertyGroup):
|
|||||||
properties: CollectionProperty(name="Properties", type=Attribute)
|
properties: CollectionProperty(name="Properties", type=Attribute)
|
||||||
pset_name: EnumProperty(items=getPsetNames, name="Pset Name")
|
pset_name: EnumProperty(items=getPsetNames, name="Pset Name")
|
||||||
qto_name: EnumProperty(items=getQtoNames, name="Qto Name")
|
qto_name: EnumProperty(items=getQtoNames, name="Qto Name")
|
||||||
|
material_pset_name: EnumProperty(items=getMaterialPsetNames, name="Pset Name")
|
||||||
|
|||||||
@@ -1,22 +1,37 @@
|
|||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.module.pset.data import Data
|
from blenderbim.bim.module.pset.data import Data
|
||||||
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
def draw_psetqto_ui(pset_id, pset, props, layout):
|
|
||||||
|
def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type):
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
row = box.row(align=True)
|
row = box.row(align=True)
|
||||||
icon = "TRIA_DOWN" if pset["is_expanded"] else "TRIA_RIGHT"
|
icon = "TRIA_DOWN" if pset["is_expanded"] else "TRIA_RIGHT"
|
||||||
row.operator("bim.toggle_pset_expansion", icon=icon, text="", emboss=False).pset_id = pset_id
|
row.operator("bim.toggle_pset_expansion", icon=icon, text="", emboss=False).pset_id = pset_id
|
||||||
if not props.active_pset_id:
|
if not props.active_pset_id:
|
||||||
row.label(text=pset["Name"], icon="COPY_ID")
|
row.label(text=pset["Name"], icon="COPY_ID")
|
||||||
row.operator("bim.enable_pset_editing", icon="GREASEPENCIL", text="").pset_id = pset_id
|
op = row.operator("bim.enable_pset_editing", icon="GREASEPENCIL", text="")
|
||||||
row.operator("bim.remove_pset", icon="X", text="").pset_id = pset_id
|
op.pset_id = pset_id
|
||||||
|
op.obj = context.active_object.name if obj_type == "Object" else context.active_object.active_material.name
|
||||||
|
op.obj_type = obj_type
|
||||||
|
op = row.operator("bim.remove_pset", icon="X", text="")
|
||||||
|
op.pset_id = pset_id
|
||||||
|
op.obj = context.active_object.name if obj_type == "Object" else context.active_object.active_material.name
|
||||||
|
op.obj_type = obj_type
|
||||||
elif props.active_pset_id != pset_id:
|
elif props.active_pset_id != pset_id:
|
||||||
row.label(text=pset["Name"], icon="COPY_ID")
|
row.label(text=pset["Name"], icon="COPY_ID")
|
||||||
row.operator("bim.remove_pset", icon="X", text="").pset_id = pset_id
|
op = row.operator("bim.remove_pset", icon="X", text="")
|
||||||
|
op.pset_id = pset_id
|
||||||
|
op.obj = context.active_object.name if obj_type == "Object" else context.active_object.active_material.name
|
||||||
|
op.obj_type = obj_type
|
||||||
elif props.active_pset_id == pset_id:
|
elif props.active_pset_id == pset_id:
|
||||||
row.prop(props, "active_pset_name", icon="COPY_ID", text="")
|
row.prop(props, "active_pset_name", icon="COPY_ID", text="")
|
||||||
row.operator("bim.edit_pset", icon="CHECKMARK", text="")
|
op = row.operator("bim.edit_pset", icon="CHECKMARK", text="")
|
||||||
row.operator("bim.disable_pset_editing", icon="X", text="")
|
op.obj = context.active_object.name if obj_type == "Object" else context.active_object.active_material.name
|
||||||
|
op.obj_type = obj_type
|
||||||
|
op = row.operator("bim.disable_pset_editing", icon="X", text="")
|
||||||
|
op.obj = context.active_object.name if obj_type == "Object" else context.active_object.active_material.name
|
||||||
|
op.obj_type = obj_type
|
||||||
if pset["is_expanded"]:
|
if pset["is_expanded"]:
|
||||||
if props.active_pset_id == pset_id:
|
if props.active_pset_id == pset_id:
|
||||||
for prop in pset["Properties"]:
|
for prop in pset["Properties"]:
|
||||||
@@ -30,6 +45,7 @@ def draw_psetqto_ui(pset_id, pset, props, layout):
|
|||||||
row.label(text=prop["Name"])
|
row.label(text=prop["Name"])
|
||||||
row.label(text=str(prop["value"]))
|
row.label(text=str(prop["value"]))
|
||||||
|
|
||||||
|
|
||||||
def draw_psetqto_editable_ui(box, props, prop):
|
def draw_psetqto_editable_ui(box, props, prop):
|
||||||
row = box.row(align=True)
|
row = box.row(align=True)
|
||||||
blender_prop = props.properties.get(prop["Name"])
|
blender_prop = props.properties.get(prop["Name"])
|
||||||
@@ -60,6 +76,7 @@ def draw_psetqto_editable_ui(box, props, prop):
|
|||||||
op = row.operator("bim.guess_quantity", icon="SPHERE", text="")
|
op = row.operator("bim.guess_quantity", icon="SPHERE", text="")
|
||||||
op.prop = prop["Name"]
|
op.prop = prop["Name"]
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_object_psets(Panel):
|
class BIM_PT_object_psets(Panel):
|
||||||
bl_label = "IFC Object Property Sets"
|
bl_label = "IFC Object Property Sets"
|
||||||
bl_idname = "BIM_PT_object_psets"
|
bl_idname = "BIM_PT_object_psets"
|
||||||
@@ -89,14 +106,16 @@ class BIM_PT_object_psets(Panel):
|
|||||||
Data.load(oprops.ifc_definition_id)
|
Data.load(oprops.ifc_definition_id)
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(props, "pset_name", text="")
|
row.prop(props, "pset_name", text="")
|
||||||
row.operator("bim.add_pset", icon="ADD", text="")
|
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||||
|
op.obj = context.active_object.name
|
||||||
|
op.obj_type = "Object"
|
||||||
|
|
||||||
for pset_id in Data.products[oprops.ifc_definition_id]["psets"]:
|
for pset_id in Data.products[oprops.ifc_definition_id]["psets"]:
|
||||||
pset = Data.psets[pset_id]
|
pset = Data.psets[pset_id]
|
||||||
draw_psetqto_ui(pset_id, pset, props, self.layout)
|
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Object")
|
||||||
|
|
||||||
# TODO reimplement. See #1222.
|
# TODO reimplement. See #1222.
|
||||||
#if props.relating_type and props.relating_type.PsetProperties.psets:
|
# if props.relating_type and props.relating_type.PsetProperties.psets:
|
||||||
# self.layout.label(text="Inherited Psets:")
|
# self.layout.label(text="Inherited Psets:")
|
||||||
# self.draw_psets_ui(props.relating_type.PsetProperties, enabled=False)
|
# self.draw_psets_ui(props.relating_type.PsetProperties, enabled=False)
|
||||||
|
|
||||||
@@ -134,4 +153,44 @@ class BIM_PT_object_qtos(Panel):
|
|||||||
|
|
||||||
for qto_id in Data.products[oprops.ifc_definition_id]["qtos"]:
|
for qto_id in Data.products[oprops.ifc_definition_id]["qtos"]:
|
||||||
qto = Data.qtos[qto_id]
|
qto = Data.qtos[qto_id]
|
||||||
draw_psetqto_ui(qto_id, qto, props, self.layout)
|
draw_psetqto_ui(context, qto_id, qto, props, self.layout, "Object")
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_PT_material_psets(Panel):
|
||||||
|
bl_label = "IFC Material Property Sets"
|
||||||
|
bl_idname = "BIM_PT_material_psets"
|
||||||
|
bl_space_type = "PROPERTIES"
|
||||||
|
bl_region_type = "WINDOW"
|
||||||
|
bl_context = "material"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not context.active_object:
|
||||||
|
return False
|
||||||
|
props = context.active_object.active_material.BIMObjectProperties
|
||||||
|
if not props.ifc_definition_id:
|
||||||
|
return False
|
||||||
|
if IfcStore.get_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(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
|
||||||
|
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(oprops.ifc_definition_id)
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.prop(props, "material_pset_name", text="")
|
||||||
|
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||||
|
op.obj = context.active_object.active_material.name
|
||||||
|
op.obj_type = "Material"
|
||||||
|
|
||||||
|
for pset_id in Data.products[oprops.ifc_definition_id]["psets"]:
|
||||||
|
pset = Data.psets[pset_id]
|
||||||
|
draw_psetqto_ui(context, pset_id, pset, props, self.layout, "Material")
|
||||||
|
|||||||
Reference in New Issue
Block a user