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
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):
for attribute in IfcStore.get_schema().declaration_by_name(ifc_class).all_attributes():
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
@@ -36,8 +36,16 @@ classes = (
operator.EnableEditingStructuralLoadCaseGroups,
operator.DisableEditingStructuralLoadCase,
operator.EnableEditingStructuralLoadGroupActivities,
operator.LoadStructuralLoads,
operator.DisableStructuralLoadEditingUI,
operator.AddStructuralLoad,
operator.EnableEditingStructuralLoad,
operator.DisableEditingStructuralLoad,
operator.RemoveStructuralLoad,
operator.EditStructuralLoad,
prop.StructuralAnalysisModel,
prop.StructuralActivity,
prop.StructuralLoad,
prop.BIMStructuralProperties,
prop.BIMObjectStructuralProperties,
ui.BIM_PT_structural_analysis_models,
@@ -48,6 +56,8 @@ classes = (
ui.BIM_UL_structural_analysis_models,
ui.BIM_UL_structural_activities,
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 mathutils import Vector, Matrix
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.structural.prop import purge
from ifcopenshell.api.structural.data import Data
from ifcopenshell.api.context.data import Data as ContextData
@@ -459,9 +460,17 @@ class EnableEditingStructuralConnectionCS(bpy.types.Operator):
empty.location = location
if item.ConditionCoordinateSystem is not None:
z_axis = 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
z_axis = (
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:
y_axis = (z_axis.cross(x_axis)).normalized()
x_axis = (y_axis.cross(z_axis)).normalized()
@@ -473,7 +482,6 @@ class EnableEditingStructuralConnectionCS(bpy.types.Operator):
(0, 0, 0, 1),
)
)
props.ccs_x_angle = degrees(empty.rotation_euler[0])
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.load_group_editing_type = "ACTIVITY"
self.load_structural_activities()
purge()
return {"FINISHED"}
def load_structural_activities(self):
@@ -709,27 +718,35 @@ class AddStructuralActivity(bpy.types.Operator):
if not obj.BIMObjectProperties.ifc_definition_id:
continue
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"):
if applied_load_class not in ["IfcStructuralLoadSingleForce", "IfcStructuralLoadSingleDisplacement"]:
continue
ifc_class = "IfcStructuralPointAction"
elif element.is_a("IfcStructuralCurveMember"):
if applied_load_class != "IfcStructuralLoadLinearForce":
continue
ifc_class = "IfcStructuralLinearAction"
elif element.is_a("IfcStructuralSurfaceMember"):
if applied_load_class != "IfcStructuralLoadPlanarForce":
continue
ifc_class = "IfcStructuralPlanarAction"
allowed_load_classes = {
"IfcStructuralPointConnection": [
"IfcStructuralLoadTemperature",
"IfcStructuralLoadSingleForce",
"IfcStructuralLoadSingleDisplacement",
],
"IfcStructuralCurveMember": ["IfcStructuralLoadTemperature", "IfcStructuralLoadLinearForce"],
"IfcStructuralSurfaceMember": ["IfcStructuralLoadTemperature", "IfcStructuralLoadPlanarForce"],
}
applicable_activity_class = {
"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(
"structural.add_structural_activity",
self.file,
ifc_class=ifc_class,
applied_load=None, # TODO
structural_member=element
applied_load=self.file.by_id(int(self.props.applicable_structural_loads)),
structural_member=element,
)
ifcopenshell.api.run(
"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())
bpy.ops.bim.enable_editing_structural_load_group_activities(load_group=self.load_group)
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 math import radians
from blenderbim.bim.prop import StrProperty, Attribute
from ifcopenshell.api.structural.data import Data
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -14,8 +15,18 @@ from bpy.props import (
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()
element_classes = set(
[
@@ -37,6 +48,31 @@ def getApplicableStructuralActivityTypes(self, context):
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):
if not self.axis_empty:
return
@@ -73,6 +109,11 @@ class StructuralActivity(PropertyGroup):
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):
structural_analysis_model_attributes: CollectionProperty(
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_attributes: CollectionProperty(name="Load Group Attributes", type=Attribute)
active_load_group_id: IntProperty(name="Active Load Group Id")
applicable_structural_activity_types: EnumProperty(
items=getApplicableStructuralActivityTypes, name="Applicable Structural Activity Types"
applicable_structural_load_types: EnumProperty(
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)
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):
@@ -1,4 +1,5 @@
import bpy
import blenderbim.bim.helper
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
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):
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.load_group = load_group["id"]
layout.template_list(
@@ -422,3 +424,65 @@ class BIM_UL_structural_activities(UIList):
row = layout.row(align=True)
row.label(text=item.name)
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"],
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"]
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 = {}
members = {}
structural_activities = {}
applied_loads = {}
structural_loads = {}
connects_structural_activities = {}
load_cases = {}
@@ -24,7 +24,7 @@ class Data:
cls.connects_structural_members = {}
cls.members = {}
cls.structural_activities = {}
cls.applied_loads = {}
cls.structural_loads = {}
cls.connects_structural_activities = {}
cls.load_cases = {}
@@ -49,6 +49,7 @@ class Data:
cls.load_structural_load_case_combinations()
cls.load_structural_load_groups()
cls.load_structural_activities()
cls.load_structural_loads()
cls.is_loaded = True
@classmethod
@@ -195,8 +196,14 @@ class Data:
cls.connects_structural_members[rel.id()] = rel_data
@classmethod
def load_applied_load(cls, applied_load):
cls.applied_loads[applied_load.id()] = applied_load.get_info()
def load_structural_loads(cls):
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
def load_connects_structural_activity(cls, rel):
@@ -206,7 +213,7 @@ class Data:
rel_data["RelatedStructuralActivity"] = rel.RelatedStructuralActivity.id()
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()
cls.connects_structural_activities[rel.id()] = rel_data
@@ -238,4 +245,4 @@ class Data:
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"])