Implement load management and assigning activities with named loads. Thanks Jesusbill!

This commit is contained in:
Dion Moult
2021-05-13 18:04:50 +10:00
parent de7ddd9b97
commit b3c918f15f
10 changed files with 338 additions and 31 deletions
+17
View File
@@ -8,6 +8,23 @@ from mathutils import Vector
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
def draw_attributes(props, layout):
for attribute in props:
row = layout.row(align=True)
if attribute.data_type == "string":
row.prop(attribute, "string_value", text=attribute.name)
elif attribute.data_type == "boolean":
row.prop(attribute, "bool_value", text=attribute.name)
elif attribute.data_type == "integer":
row.prop(attribute, "int_value", text=attribute.name)
elif attribute.data_type == "float":
row.prop(attribute, "float_value", text=attribute.name)
elif attribute.data_type == "enum":
row.prop(attribute, "enum_value", text=attribute.name)
if attribute.is_optional:
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
def import_attributes(ifc_class, props, data, callback=None): def import_attributes(ifc_class, props, data, callback=None):
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes(): for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute) data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
@@ -36,8 +36,16 @@ classes = (
operator.EnableEditingStructuralLoadCaseGroups, operator.EnableEditingStructuralLoadCaseGroups,
operator.DisableEditingStructuralLoadCase, operator.DisableEditingStructuralLoadCase,
operator.EnableEditingStructuralLoadGroupActivities, operator.EnableEditingStructuralLoadGroupActivities,
operator.LoadStructuralLoads,
operator.DisableStructuralLoadEditingUI,
operator.AddStructuralLoad,
operator.EnableEditingStructuralLoad,
operator.DisableEditingStructuralLoad,
operator.RemoveStructuralLoad,
operator.EditStructuralLoad,
prop.StructuralAnalysisModel, prop.StructuralAnalysisModel,
prop.StructuralActivity, prop.StructuralActivity,
prop.StructuralLoad,
prop.BIMStructuralProperties, prop.BIMStructuralProperties,
prop.BIMObjectStructuralProperties, prop.BIMObjectStructuralProperties,
ui.BIM_PT_structural_analysis_models, ui.BIM_PT_structural_analysis_models,
@@ -48,6 +56,8 @@ classes = (
ui.BIM_UL_structural_analysis_models, ui.BIM_UL_structural_analysis_models,
ui.BIM_UL_structural_activities, ui.BIM_UL_structural_activities,
ui.BIM_PT_structural_load_cases, ui.BIM_PT_structural_load_cases,
ui.BIM_UL_structural_loads,
ui.BIM_PT_structural_loads,
) )
@@ -6,6 +6,7 @@ import blenderbim.bim.helper
from math import degrees from math import degrees
from mathutils import Vector, Matrix from mathutils import Vector, Matrix
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.structural.prop import purge
from ifcopenshell.api.structural.data import Data from ifcopenshell.api.structural.data import Data
from ifcopenshell.api.context.data import Data as ContextData from ifcopenshell.api.context.data import Data as ContextData
@@ -459,9 +460,17 @@ class EnableEditingStructuralConnectionCS(bpy.types.Operator):
empty.location = location empty.location = location
if item.ConditionCoordinateSystem is not None: if item.ConditionCoordinateSystem is not None:
z_axis = Vector(item.ConditionCoordinateSystem.Axis.DirectionRatios).normalized() @ obj.matrix_world if item.ConditionCoordinateSystem.Axis else None z_axis = (
x_axis = Vector(item.ConditionCoordinateSystem.RefDirection.DirectionRatios).normalized() @ obj.matrix_world if item.ConditionCoordinateSystem.RefDirection else None Vector(item.ConditionCoordinateSystem.Axis.DirectionRatios).normalized() @ obj.matrix_world
if item.ConditionCoordinateSystem.Axis
else None
)
x_axis = (
Vector(item.ConditionCoordinateSystem.RefDirection.DirectionRatios).normalized() @ obj.matrix_world
if item.ConditionCoordinateSystem.RefDirection
else None
)
if z_axis: if z_axis:
y_axis = (z_axis.cross(x_axis)).normalized() y_axis = (z_axis.cross(x_axis)).normalized()
x_axis = (y_axis.cross(z_axis)).normalized() x_axis = (y_axis.cross(z_axis)).normalized()
@@ -473,7 +482,6 @@ class EnableEditingStructuralConnectionCS(bpy.types.Operator):
(0, 0, 0, 1), (0, 0, 0, 1),
) )
) )
props.ccs_x_angle = degrees(empty.rotation_euler[0]) props.ccs_x_angle = degrees(empty.rotation_euler[0])
props.ccs_y_angle = degrees(empty.rotation_euler[1]) props.ccs_y_angle = degrees(empty.rotation_euler[1])
@@ -684,6 +692,7 @@ class EnableEditingStructuralLoadGroupActivities(bpy.types.Operator):
self.props.active_load_group_id = self.load_group self.props.active_load_group_id = self.load_group
self.props.load_group_editing_type = "ACTIVITY" self.props.load_group_editing_type = "ACTIVITY"
self.load_structural_activities() self.load_structural_activities()
purge()
return {"FINISHED"} return {"FINISHED"}
def load_structural_activities(self): def load_structural_activities(self):
@@ -709,27 +718,35 @@ class AddStructuralActivity(bpy.types.Operator):
if not obj.BIMObjectProperties.ifc_definition_id: if not obj.BIMObjectProperties.ifc_definition_id:
continue continue
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
applied_load_class = self.props.applicable_structural_activity_types applied_load_class = self.props.applicable_structural_load_types
if element.is_a("IfcStructuralPointConnection"): allowed_load_classes = {
if applied_load_class not in ["IfcStructuralLoadSingleForce", "IfcStructuralLoadSingleDisplacement"]: "IfcStructuralPointConnection": [
continue "IfcStructuralLoadTemperature",
ifc_class = "IfcStructuralPointAction" "IfcStructuralLoadSingleForce",
elif element.is_a("IfcStructuralCurveMember"): "IfcStructuralLoadSingleDisplacement",
if applied_load_class != "IfcStructuralLoadLinearForce": ],
continue "IfcStructuralCurveMember": ["IfcStructuralLoadTemperature", "IfcStructuralLoadLinearForce"],
ifc_class = "IfcStructuralLinearAction" "IfcStructuralSurfaceMember": ["IfcStructuralLoadTemperature", "IfcStructuralLoadPlanarForce"],
elif element.is_a("IfcStructuralSurfaceMember"): }
if applied_load_class != "IfcStructuralLoadPlanarForce":
continue applicable_activity_class = {
ifc_class = "IfcStructuralPlanarAction" "IfcStructuralPointConnection": "IfcStructuralPointAction",
"IfcStructuralCurveMember": "IfcStructuralLinearAction",
"IfcStructuralSurfaceMember": "IfcStructuralPlanarAction",
}
if applied_load_class not in allowed_load_classes[element.is_a()]:
continue
ifc_class = applicable_activity_class[element.is_a()]
activity = ifcopenshell.api.run( activity = ifcopenshell.api.run(
"structural.add_structural_activity", "structural.add_structural_activity",
self.file, self.file,
ifc_class=ifc_class, ifc_class=ifc_class,
applied_load=None, # TODO applied_load=self.file.by_id(int(self.props.applicable_structural_loads)),
structural_member=element structural_member=element,
) )
ifcopenshell.api.run( ifcopenshell.api.run(
"group.assign_group", self.file, product=activity, group=self.file.by_id(self.load_group) "group.assign_group", self.file, product=activity, group=self.file.by_id(self.load_group)
@@ -737,3 +754,108 @@ class AddStructuralActivity(bpy.types.Operator):
Data.load(IfcStore.get_file()) Data.load(IfcStore.get_file())
bpy.ops.bim.enable_editing_structural_load_group_activities(load_group=self.load_group) bpy.ops.bim.enable_editing_structural_load_group_activities(load_group=self.load_group)
return {"FINISHED"} return {"FINISHED"}
class LoadStructuralLoads(bpy.types.Operator):
bl_idname = "bim.load_structural_loads"
bl_label = "Load Structural Loads"
def execute(self, context):
props = context.scene.BIMStructuralProperties
while len(props.structural_loads) > 0:
props.structural_loads.remove(0)
for ifc_definition_id, structural_loads in Data.structural_loads.items():
new = props.structural_loads.add()
new.ifc_definition_id = ifc_definition_id
new.name = structural_loads["Name"] or "Unnamed"
props.is_editing_loads = True
bpy.ops.bim.disable_editing_structural_load()
return {"FINISHED"}
class DisableStructuralLoadEditingUI(bpy.types.Operator):
bl_idname = "bim.disable_structural_load_editing_ui"
bl_label = "Disable Structural Load Editing UI"
def execute(self, context):
context.scene.BIMStructuralProperties.is_editing_loads = False
return {"FINISHED"}
class AddStructuralLoad(bpy.types.Operator):
bl_idname = "bim.add_structural_load"
bl_label = "Add Structural Load"
ifc_class: bpy.props.StringProperty()
def execute(self, context):
result = ifcopenshell.api.run(
"structural.add_structural_load", IfcStore.get_file(), name="New Load", ifc_class=self.ifc_class
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_structural_loads()
bpy.ops.bim.enable_editing_structural_load(structural_load=result.id())
return {"FINISHED"}
class EnableEditingStructuralLoad(bpy.types.Operator):
bl_idname = "bim.enable_editing_structural_load"
bl_label = "Enable Editing Structural Load"
structural_load: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMStructuralProperties
while len(props.structural_load_attributes) > 0:
props.structural_load_attributes.remove(0)
data = Data.structural_loads[self.structural_load]
blenderbim.bim.helper.import_attributes(data["type"], props.structural_load_attributes, data)
props.active_structural_load_id = self.structural_load
return {"FINISHED"}
class DisableEditingStructuralLoad(bpy.types.Operator):
bl_idname = "bim.disable_editing_structural_load"
bl_label = "Disable Editing Structural Load"
def execute(self, context):
context.scene.BIMStructuralProperties.active_structural_load_id = 0
return {"FINISHED"}
class RemoveStructuralLoad(bpy.types.Operator):
bl_idname = "bim.remove_structural_load"
bl_label = "Remove Structural Load"
structural_load: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMStructuralProperties
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"structural.remove_structural_load",
self.file,
**{"structural_load": self.file.by_id(self.structural_load)},
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_structural_loads()
return {"FINISHED"}
class EditStructuralLoad(bpy.types.Operator):
bl_idname = "bim.edit_structural_load"
bl_label = "Edit Structural Load"
def execute(self, context):
props = context.scene.BIMStructuralProperties
attributes = blenderbim.bim.helper.export_attributes(props.structural_load_attributes)
self.file = IfcStore.get_file()
ifcopenshell.api.run(
"structural.edit_structural_load",
self.file,
**{
"structural_load": self.file.by_id(props.active_structural_load_id),
"attributes": attributes,
},
)
Data.load(IfcStore.get_file())
bpy.ops.bim.load_structural_loads()
return {"FINISHED"}
@@ -2,6 +2,7 @@ import bpy
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from math import radians from math import radians
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
from ifcopenshell.api.structural.data import Data
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
from bpy.props import ( from bpy.props import (
PointerProperty, PointerProperty,
@@ -14,8 +15,18 @@ from bpy.props import (
CollectionProperty, CollectionProperty,
) )
structuralloadtypes_enum = []
applicablestructuralloads_enum = []
def getApplicableStructuralActivityTypes(self, context):
def purge():
global structuralloadtypes_enum
global applicablestructuralloads_enum
structuralloadtypes_enum = []
applicablestructuralloads_enum = []
def getApplicableStructuralLoadTypes(self, context):
ifc_file = IfcStore.get_file() ifc_file = IfcStore.get_file()
element_classes = set( element_classes = set(
[ [
@@ -37,6 +48,31 @@ def getApplicableStructuralActivityTypes(self, context):
return types return types
def updateApplicableStructuralLoadTypes(self, context):
global applicablestructuralloads_enum
applicablestructuralloads_enum.clear()
def getApplicableStructuralLoads(self, context):
global applicablestructuralloads_enum
file = IfcStore.get_file()
if len(applicablestructuralloads_enum) < 1 and file:
for ifc_definition_id, load in Data.structural_loads.items():
if not load["Name"] or load["type"] != self.applicable_structural_load_types:
continue
applicablestructuralloads_enum.append((str(ifc_definition_id), load["Name"], ""))
return applicablestructuralloads_enum
def getStructuralLoadTypes(self, context):
global structuralloadtypes_enum
file = IfcStore.get_file()
if len(structuralloadtypes_enum) < 1 and file:
declaration = IfcStore.get_schema().declaration_by_name("IfcStructuralLoadStatic")
structuralloadtypes_enum.extend([(d.name(), d.name(), "") for d in declaration.subtypes()])
return structuralloadtypes_enum
def updateAxisAngle(self, context): def updateAxisAngle(self, context):
if not self.axis_empty: if not self.axis_empty:
return return
@@ -73,6 +109,11 @@ class StructuralActivity(PropertyGroup):
ifc_definition_id: IntProperty(name="IFC Definition ID") ifc_definition_id: IntProperty(name="IFC Definition ID")
class StructuralLoad(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
class BIMStructuralProperties(PropertyGroup): class BIMStructuralProperties(PropertyGroup):
structural_analysis_model_attributes: CollectionProperty( structural_analysis_model_attributes: CollectionProperty(
name="Structural Analysis Model Attributes", type=Attribute name="Structural Analysis Model Attributes", type=Attribute
@@ -87,11 +128,21 @@ class BIMStructuralProperties(PropertyGroup):
load_group_editing_type: StringProperty(name="Load Group Editing Type") load_group_editing_type: StringProperty(name="Load Group Editing Type")
# load_group_attributes: CollectionProperty(name="Load Group Attributes", type=Attribute) # load_group_attributes: CollectionProperty(name="Load Group Attributes", type=Attribute)
active_load_group_id: IntProperty(name="Active Load Group Id") active_load_group_id: IntProperty(name="Active Load Group Id")
applicable_structural_activity_types: EnumProperty( applicable_structural_load_types: EnumProperty(
items=getApplicableStructuralActivityTypes, name="Applicable Structural Activity Types" items=getApplicableStructuralLoadTypes, name="Applicable Structural Load Types",
update=updateApplicableStructuralLoadTypes
)
applicable_structural_loads: EnumProperty(
items=getApplicableStructuralLoads, name="Applicable Structural Loads"
) )
load_group_activities: CollectionProperty(name="Load Group Activities", type=StructuralActivity) load_group_activities: CollectionProperty(name="Load Group Activities", type=StructuralActivity)
active_load_group_activity_index: IntProperty(name="Active Load Group Activity Index") active_load_group_activity_index: IntProperty(name="Active Load Group Activity Index")
structural_loads: CollectionProperty(name="Structural Loads", type=StructuralLoad)
active_structural_load_index: IntProperty(name="Active Structural Load Index")
active_structural_load_id: IntProperty(name="Active Structural Load Id")
is_editing_loads: BoolProperty(name="Is Editing Loads", default=False)
structural_load_types: EnumProperty(items=getStructuralLoadTypes, name="Structural Load Types")
structural_load_attributes: CollectionProperty(name="Structural Load Attributes", type=Attribute)
class BIMObjectStructuralProperties(PropertyGroup): class BIMObjectStructuralProperties(PropertyGroup):
@@ -1,4 +1,5 @@
import bpy import bpy
import blenderbim.bim.helper
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.structural.data import Data from ifcopenshell.api.structural.data import Data
@@ -402,7 +403,8 @@ class BIM_PT_structural_load_cases(Panel):
def draw_editable_load_group_activities_ui(self, layout, load_group): def draw_editable_load_group_activities_ui(self, layout, load_group):
row = layout.row(align=True) row = layout.row(align=True)
row.prop(self.props, "applicable_structural_activity_types", text="") row.prop(self.props, "applicable_structural_load_types", text="")
row.prop(self.props, "applicable_structural_loads", text="")
op = row.operator("bim.add_structural_activity", text="", icon="ADD") op = row.operator("bim.add_structural_activity", text="", icon="ADD")
op.load_group = load_group["id"] op.load_group = load_group["id"]
layout.template_list( layout.template_list(
@@ -422,3 +424,65 @@ class BIM_UL_structural_activities(UIList):
row = layout.row(align=True) row = layout.row(align=True)
row.label(text=item.name) row.label(text=item.name)
row.label(text=item.applied_load_class) row.label(text=item.applied_load_class)
class BIM_PT_structural_loads(Panel):
bl_label = "IFC Structural Loads"
bl_idname = "BIM_PT_structural_loads"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
@classmethod
def poll(cls, context):
return IfcStore.get_file()
def draw(self, context):
if not Data.is_loaded:
Data.load(IfcStore.get_file())
self.props = context.scene.BIMStructuralProperties
row = self.layout.row(align=True)
row.label(
text="{} Structural Loads Found".format(len(Data.structural_loads)), icon="GHOST_ENABLED"
)
if self.props.is_editing_loads:
row.prop(self.props, "structural_load_types", text="")
row.operator("bim.add_structural_load", text="", icon="ADD").ifc_class = self.props.structural_load_types
row.operator("bim.disable_structural_load_editing_ui", text="", icon="CANCEL")
else:
row.operator("bim.load_structural_loads", text="", icon="GREASEPENCIL")
if self.props.is_editing_loads:
self.layout.template_list(
"BIM_UL_structural_loads",
"",
self.props,
"structural_loads",
self.props,
"active_structural_load_index",
)
if self.props.active_structural_load_id:
blenderbim.bim.helper.draw_attributes(self.props.structural_load_attributes, self.layout)
class BIM_UL_structural_loads(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
row.label(text=item.name)
row.label(text=Data.structural_loads[item.ifc_definition_id]["type"])
if context.scene.BIMStructuralProperties.active_structural_load_id == item.ifc_definition_id:
row.operator("bim.edit_structural_load", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_structural_load", text="", icon="CANCEL")
elif context.scene.BIMStructuralProperties.active_structural_load_id:
op = row.operator("bim.remove_structural_load", text="", icon="X")
op.structural_load = item.ifc_definition_id
else:
op = row.operator("bim.enable_editing_structural_load", text="", icon="GREASEPENCIL")
op.structural_load = item.ifc_definition_id
op = row.operator("bim.remove_structural_load", text="", icon="X")
op.structural_load = item.ifc_definition_id
@@ -21,8 +21,7 @@ class Usecase:
ifc_class=self.settings["ifc_class"], ifc_class=self.settings["ifc_class"],
predefined_type=self.settings["predefined_type"], predefined_type=self.settings["predefined_type"],
) )
# TODO activity.AppliedLoad = self.settings["applied_load"]
# activity.AppliedLoad = self.settings["applied_load"]
activity.GlobalOrLocal = self.settings["global_or_local"] activity.GlobalOrLocal = self.settings["global_or_local"]
rel = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcRelConnectsStructuralActivity") rel = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcRelConnectsStructuralActivity")
@@ -0,0 +1,15 @@
import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
self.file = file
self.settings = {
"name": None,
"ifc_class": "IfcStructuralLoadLinearForce",
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
return self.file.create_entity(self.settings["ifc_class"], Name=self.settings["name"])
@@ -7,7 +7,7 @@ class Data:
connects_structural_members = {} connects_structural_members = {}
members = {} members = {}
structural_activities = {} structural_activities = {}
applied_loads = {} structural_loads = {}
connects_structural_activities = {} connects_structural_activities = {}
load_cases = {} load_cases = {}
@@ -24,7 +24,7 @@ class Data:
cls.connects_structural_members = {} cls.connects_structural_members = {}
cls.members = {} cls.members = {}
cls.structural_activities = {} cls.structural_activities = {}
cls.applied_loads = {} cls.structural_loads = {}
cls.connects_structural_activities = {} cls.connects_structural_activities = {}
cls.load_cases = {} cls.load_cases = {}
@@ -49,6 +49,7 @@ class Data:
cls.load_structural_load_case_combinations() cls.load_structural_load_case_combinations()
cls.load_structural_load_groups() cls.load_structural_load_groups()
cls.load_structural_activities() cls.load_structural_activities()
cls.load_structural_loads()
cls.is_loaded = True cls.is_loaded = True
@classmethod @classmethod
@@ -195,8 +196,14 @@ class Data:
cls.connects_structural_members[rel.id()] = rel_data cls.connects_structural_members[rel.id()] = rel_data
@classmethod @classmethod
def load_applied_load(cls, applied_load): def load_structural_loads(cls):
cls.applied_loads[applied_load.id()] = applied_load.get_info() cls.structural_loads = {}
for load in cls._file.by_type("IfcStructuralLoad"):
cls.load_structural_load(load)
@classmethod
def load_structural_load(cls, load):
cls.structural_loads[load.id()] = load.get_info()
@classmethod @classmethod
def load_connects_structural_activity(cls, rel): def load_connects_structural_activity(cls, rel):
@@ -206,7 +213,7 @@ class Data:
rel_data["RelatedStructuralActivity"] = rel.RelatedStructuralActivity.id() rel_data["RelatedStructuralActivity"] = rel.RelatedStructuralActivity.id()
if rel.RelatedStructuralActivity.AppliedLoad: if rel.RelatedStructuralActivity.AppliedLoad:
cls.load_applied_load(rel.RelatedStructuralActivity.AppliedLoad) cls.load_structural_load(rel.RelatedStructuralActivity.AppliedLoad)
# rel_data["AppliedCondition"] = rel.RelatedStructuralActivity.AppliedLoad.id() # rel_data["AppliedCondition"] = rel.RelatedStructuralActivity.AppliedLoad.id()
cls.connects_structural_activities[rel.id()] = rel_data cls.connects_structural_activities[rel.id()] = rel_data
@@ -238,4 +245,4 @@ class Data:
data["ConnectedBy"].append(rel.id()) data["ConnectedBy"].append(rel.id())
cls.members[member.id()] = data cls.members[member.id()] = data
@@ -0,0 +1,13 @@
class Usecase:
def __init__(self, file, **settings):
self.file = file
self.settings = {
"structural_load": None,
"attributes": {}
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
for name, value in self.settings["attributes"].items():
setattr(self.settings["structural_load"], name, value)
@@ -0,0 +1,9 @@
class Usecase:
def __init__(self, file, **settings):
self.file = file
self.settings = {"structural_load": None}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
self.file.remove(self.settings["structural_load"])