This commit is contained in:
Andrej730
2025-03-14 10:43:47 +05:00
parent 10ecac33b8
commit 0e8810c1f5
118 changed files with 869 additions and 1203 deletions
+1 -1
View File
@@ -380,7 +380,7 @@ class BIM_PT_object_qtos(Panel):
filter_keyword=context.scene.GlobalPsetProperties.qto_filter,
)
layout = self.layout
qtoprops = context.scene.BIMQtoProperties
qtoprops = tool.Qto.get_qto_props()
row = layout.row(align=True)
row.prop(qtoprops, "qto_rule", text="")
# A bit confusing as we typically use this icon for is_null.
@@ -76,6 +76,7 @@ def get_length(o: bpy.types.Object, vg_index: Optional[int] = None) -> float:
return max(y, z)
length = 0
assert isinstance(o.data, bpy.types.Mesh)
edges = [
e
for e in o.data.edges
@@ -269,6 +270,7 @@ def get_net_perimeter(o: bpy.types.Object) -> float:
def get_gross_perimeter(o: bpy.types.Object) -> float:
element = tool.Ifc.get_entity(o)
assert element
mesh = get_gross_element_mesh(element)
gross_obj = bpy.data.objects.new("GrossObj", mesh)
gross_perimeter = get_net_perimeter(gross_obj)
@@ -420,6 +422,7 @@ def get_gross_footprint_area(o: bpy.types.Object) -> float:
return get_net_footprint_area(o)
element = tool.Ifc.get_entity(o)
assert element
mesh = get_gross_element_mesh(element)
gross_obj = bpy.data.objects.new("GrossObj", mesh)
gross_footprint_area = get_net_footprint_area(gross_obj)
@@ -474,6 +477,7 @@ def get_gross_surface_area(o: bpy.types.Object, vg_index: Optional[int] = None)
return get_net_surface_area(o)
element = tool.Ifc.get_entity(o)
assert element
mesh = get_gross_element_mesh(element)
area = get_mesh_area(mesh)
bpy.data.meshes.remove(mesh)
@@ -506,6 +510,7 @@ def is_polygon_in_vg(polygon: bpy.types.MeshPolygon, vertices_in_vg: list[bpy.ty
def get_net_volume(o: bpy.types.Object) -> float:
assert isinstance(o.data, bpy.types.Mesh)
o_mesh = bmesh.new()
o_mesh.from_mesh(o.data)
volume = o_mesh.calc_volume()
@@ -518,6 +523,7 @@ def get_gross_volume(o: bpy.types.Object) -> float:
return get_net_volume(o)
element = tool.Ifc.get_entity(o)
assert element
mesh = get_gross_element_mesh(element)
bm = get_bmesh_from_mesh(mesh)
@@ -562,6 +568,7 @@ def get_net_weight(obj: bpy.types.Object) -> Union[float, None]:
def get_obj_mass_density(obj: bpy.types.Object) -> Union[float, None]:
entity = tool.Ifc.get_entity(obj)
assert entity
material = ifcopenshell.util.element.get_material(entity)
if material is None:
return
@@ -764,6 +771,7 @@ def get_outer_surface_area(obj: bpy.types.Object) -> float:
def get_end_area(obj: bpy.types.Object) -> float:
element = tool.Ifc.get_entity(obj)
assert element
gross_mesh = get_gross_element_mesh(element)
gross_obj = bpy.data.objects.new("MyObject", gross_mesh)
@@ -51,6 +51,7 @@ def calculate_mesh_quantity(
result = 0
edit_mode = context.active_object.mode == "EDIT"
for obj in objs:
assert isinstance(obj.data, bpy.types.Mesh)
if edit_mode:
bm = bmesh.from_edit_mesh(obj.data)
result += operation(bm)
+7 -7
View File
@@ -49,7 +49,7 @@ class CalculateEdgeLengths(bpy.types.Operator):
def execute(self, context):
result = helper.calculate_edges_lengths([o for o in context.selected_objects if o.type == "MESH"], context)
context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
tool.Qto.set_qto_result(result)
return {"FINISHED"}
@@ -64,7 +64,7 @@ class CalculateFaceAreas(bpy.types.Operator):
def execute(self, context):
result = helper.calculate_faces_areas([o for o in context.selected_objects if o.type == "MESH"], context)
context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
tool.Qto.set_qto_result(result)
return {"FINISHED"}
@@ -79,7 +79,7 @@ class CalculateObjectVolumes(bpy.types.Operator):
def execute(self, context):
result = helper.calculate_volumes([o for o in context.selected_objects if o.type == "MESH"], context)
context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
tool.Qto.set_qto_result(result)
return {"FINISHED"}
@@ -94,7 +94,7 @@ class CalculateFormworkArea(bpy.types.Operator):
def execute(self, context):
result = helper.calculate_formwork_area([o for o in context.selected_objects if o.type == "MESH"], context)
context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
tool.Qto.set_qto_result(result)
return {"FINISHED"}
@@ -109,7 +109,7 @@ class CalculateSideFormworkArea(bpy.types.Operator):
def execute(self, context):
result = helper.calculate_side_formwork_area([o for o in context.selected_objects if o.type == "MESH"], context)
context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
tool.Qto.set_qto_result(result)
return {"FINISHED"}
@@ -126,7 +126,7 @@ class CalculateSingleQuantity(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
import ifc5d.qto
props = context.scene.BIMQtoProperties
props = tool.Qto.get_qto_props()
elements = set()
for obj in tool.Blender.get_selected_objects(include_active=False):
element = tool.Ifc.get_entity(obj)
@@ -163,7 +163,7 @@ class PerformQuantityTakeOff(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
import ifc5d.qto
props = context.scene.BIMQtoProperties
props = tool.Qto.get_qto_props()
elements: set[ifcopenshell.entity_instance]
if context.selected_objects:
+23 -6
View File
@@ -31,12 +31,16 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Union
def get_qto_rule(self, context):
CALCULATOR_FUNCTION_ENUM_ITEMS: list[Union[tuple[str, str, str], None]] = []
def get_qto_rule(self: "BIMQtoProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
ifc_file = tool.Ifc.get()
is_ifc4x3 = ifc_file.schema == "IFC4X3"
results = []
results: list[tuple[str, str, str]] = []
for rule_id, rule in ifc5d.qto.rules.items():
if rule_id.startswith("IFC4X3") != is_ifc4x3:
continue
@@ -44,14 +48,16 @@ def get_qto_rule(self, context):
return results
def get_calculator(self, context):
results = []
def get_calculator(self: "BIMQtoProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
results: list[tuple[str, str, str]] = []
for name, calculator in ifc5d.qto.calculators.items():
results.append((name, name, calculator.__doc__))
results.append((name, name, calculator.__doc__ or ""))
return results
def get_calculator_function(self, context):
def get_calculator_function(
self: "BIMQtoProperties", context: bpy.types.Context
) -> list[Union[tuple[str, str, str], None]]:
global CALCULATOR_FUNCTION_ENUM_ITEMS
calculator = ifc5d.qto.calculators[self.calculator]
CALCULATOR_FUNCTION_ENUM_ITEMS = []
@@ -60,6 +66,8 @@ def get_calculator_function(self, context):
measure = function.measure.split("Measure")[0][3:]
if previous_measure is not None and measure != previous_measure:
CALCULATOR_FUNCTION_ENUM_ITEMS.append(None)
description = function.description
description += f"\n\nInternal function id: '{function_id}'."
CALCULATOR_FUNCTION_ENUM_ITEMS.append((function_id, f"{measure}: {function.name}", function.description))
previous_measure = measure
return CALCULATOR_FUNCTION_ENUM_ITEMS
@@ -80,3 +88,12 @@ class BIMQtoProperties(PropertyGroup):
),
default=False,
)
if TYPE_CHECKING:
qto_rule: str
calculator: str
calculator_function: str
qto_result: str
qto_name: str
prop_name: str
fallback: bool
+4 -3
View File
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from bonsai.bim.module.qto.data import QtoData
@@ -32,7 +33,7 @@ class BIM_PT_qto(bpy.types.Panel):
def draw(self, context):
layout = self.layout
props = context.scene.BIMQtoProperties
props = tool.Qto.get_qto_props()
row = layout.row()
if context.selected_objects:
@@ -57,7 +58,7 @@ class BIM_PT_qto_manual(bpy.types.Panel):
def draw(self, context):
layout = self.layout
props = context.scene.BIMQtoProperties
props = tool.Qto.get_qto_props()
row = layout.row()
row.prop(props, "calculator")
@@ -83,7 +84,7 @@ class BIM_PT_qto_simple(bpy.types.Panel):
def draw(self, context):
layout = self.layout
props = context.scene.BIMQtoProperties
props = tool.Qto.get_qto_props()
row = layout.row()
row.prop(props, "qto_result", text="Results")
@@ -59,7 +59,7 @@ class LoadGroupDecorationData:
return ret
m = models[0]
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
if props.activity_type == "Action":
groups = m.LoadedBy or []
for g in groups:
@@ -128,7 +128,8 @@ class ConnectedStructuralMembersData:
if not element:
return []
results = []
props = bpy.context.active_object.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
for rel in element.ConnectsStructuralMembers or []:
condition = rel.AppliedCondition
if condition:
@@ -257,7 +258,7 @@ class StructuralLoadCasesData:
@classmethod
def applicable_structural_loads(cls):
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
results = []
for load in tool.Ifc.get().by_type("IfcStructuralLoad"):
if not load.Name or not load.is_a(props.applicable_structural_load_types):
@@ -24,6 +24,7 @@ from mathutils import Vector
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.attribute
import ifcopenshell.util.placement
import ifcopenshell.util.unit as ifcunit
import bonsai.tool as tool
from bonsai.bim.module.structural.shader import DecorationShader
@@ -304,7 +305,7 @@ class ShaderInfo:
populate_members_dict("surface_members", element, activity, factor)
recursive_subgroups(subgorups, rec_limit - 1, activity_type, factor=factor)
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
group_definition_id = int(props.load_group_to_show)
file = tool.Ifc.get()
groups = [file.by_id(group_definition_id)]
@@ -327,7 +328,7 @@ class ShaderInfo:
maximum = max([abs(float(i)) for i in values])
if maximum == 0:
continue
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
reference_frame = props.reference_frame
orientation = np.eye(3)
if reference_frame == "LOCAL_COORDS":
@@ -435,7 +436,7 @@ class ShaderInfo:
) -> np.ndarray:
"provides the transformation matrix to convert between reference frames"
global_or_local = activity.GlobalOrLocal
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
reference_frame = props.reference_frame
transform_matrix = np.eye(3)
if reference_frame == "LOCAL_COORDS" and global_or_local != reference_frame:
@@ -473,7 +474,7 @@ class ShaderInfo:
"mz": (np.array((1, 0, 0)), np.array((0, 1, 0))),
}
keys = ["fx", "fy", "fz", "mx", "my", "mz"]
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
reference_frame = props.reference_frame
if reference_frame == "LOCAL_COORDS":
for key in keys:
@@ -591,7 +592,7 @@ class ShaderInfo:
z_axis = x_axis.cross(y_axis).normalized()
rotation = self.get_curve_member_rotation(member)
props = bpy.context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
reference_frame = props.reference_frame
is_local = reference_frame == "LOCAL_COORDS"
x_match = abs(Vector((1, 0, 0)).dot(x_axis)) > 0.99
@@ -20,6 +20,7 @@ import bpy
import json
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.api.group
import ifcopenshell.api.structural
import ifcopenshell.util.attribute
import bonsai.bim.helper
@@ -77,7 +78,7 @@ class AddStructuralMemberConnection(bpy.types.Operator, tool.Ifc.Operator):
obj = context.active_object
assert obj
oprops = tool.Blender.get_object_bim_props(obj)
props = obj.BIMStructuralProperties
props = tool.Structural.get_object_structural_props(obj)
file = tool.Ifc.get()
related_structural_connection = file.by_id(oprops.ifc_definition_id)
relating_structural_member = tool.Ifc.get_entity(props.relating_structural_member)
@@ -101,7 +102,8 @@ class EnableEditingStructuralConnectionCondition(bpy.types.Operator):
def execute(self, context):
obj = context.active_object
props = obj.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
props.active_connects_structural_member = self.connects_structural_member
return {"FINISHED"}
@@ -113,7 +115,8 @@ class DisableEditingStructuralConnectionCondition(bpy.types.Operator):
def execute(self, context):
obj = context.active_object
props = obj.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
props.active_connects_structural_member = 0
return {"FINISHED"}
@@ -166,7 +169,8 @@ class EnableEditingStructuralBoundaryCondition(bpy.types.Operator):
def execute(self, context):
obj = context.active_object
props = obj.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
props.boundary_condition_attributes.clear()
condition = tool.Ifc.get().by_id(self.boundary_condition)
@@ -206,7 +210,8 @@ class EditStructuralBoundaryCondition(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
obj = context.active_object
props = obj.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
file = tool.Ifc.get()
connection = file.by_id(self.connection)
@@ -236,7 +241,10 @@ class DisableEditingStructuralBoundaryCondition(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.active_object.BIMStructuralProperties.active_boundary_condition = 0
obj = context.active_object
assert obj
props = tool.Structural.get_object_structural_props(obj)
props.active_boundary_condition = 0
return {"FINISHED"}
@@ -353,7 +361,7 @@ class EnableEditingStructuralItemAxis(bpy.types.Operator):
obj = context.active_object
assert obj
oprops = tool.Blender.get_object_bim_props(obj)
props = obj.BIMStructuralProperties
props = tool.Structural.get_object_structural_props(obj)
self.file = tool.Ifc.get()
item = self.file.by_id(oprops.ifc_definition_id)
@@ -392,7 +400,8 @@ class DisableEditingStructuralItemAxis(bpy.types.Operator):
def execute(self, context):
obj = context.active_object
props = obj.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
props.is_editing_axis = False
if props.axis_empty:
bpy.data.objects.remove(props.axis_empty)
@@ -407,7 +416,7 @@ class EditStructuralItemAxis(bpy.types.Operator, tool.Ifc.Operator):
obj = context.active_object
assert obj
oprops = tool.Blender.get_object_bim_props(obj)
props = obj.BIMStructuralProperties
props = tool.Structural.get_object_structural_props(obj)
relative_matrix = props.axis_empty.matrix_world @ obj.matrix_world.inverted()
z_axis = relative_matrix.col[2][0:3]
self.file = tool.Ifc.get()
@@ -429,7 +438,7 @@ class EnableEditingStructuralConnectionCS(bpy.types.Operator):
def execute(self, context):
obj = context.active_object
assert obj
props = obj.BIMStructuralProperties
props = tool.Structural.get_object_structural_props(obj)
self.file = tool.Ifc.get()
item = tool.Ifc.get_entity(obj)
@@ -481,7 +490,8 @@ class DisableEditingStructuralConnectionCS(bpy.types.Operator):
def execute(self, context):
obj = context.active_object
props = obj.BIMStructuralProperties
assert obj
props = tool.Structural.get_object_structural_props(obj)
props.is_editing_connection_cs = False
if props.ccs_empty:
bpy.data.objects.remove(props.ccs_empty)
@@ -498,7 +508,7 @@ class EditStructuralConnectionCS(bpy.types.Operator, tool.Ifc.Operator):
assert obj
item = tool.Ifc.get_entity(obj)
assert item
props = obj.BIMStructuralProperties
props = tool.Structural.get_object_structural_props(obj)
relative_matrix = props.ccs_empty.matrix_world @ obj.matrix_world.inverted()
x_axis = relative_matrix.col[0][0:3]
z_axis = relative_matrix.col[2][0:3]
@@ -567,13 +577,13 @@ class EditStructuralLoadCase(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
attributes = bonsai.bim.helper.export_attributes(props.load_case_attributes)
self.file = tool.Ifc.get()
ifcopenshell.api.run(
"structural.edit_structural_load_case",
ifcopenshell.api.structural.edit_structural_load_case(
self.file,
**{"load_case": self.file.by_id(props.active_load_case_id), "attributes": attributes},
load_case=self.file.by_id(props.active_load_case_id),
attributes=attributes,
)
bpy.ops.bim.disable_editing_structural_load_case()
return {"FINISHED"}
@@ -587,9 +597,7 @@ class RemoveStructuralLoadCase(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
self.file = tool.Ifc.get()
ifcopenshell.api.run(
"structural.remove_structural_load_case", self.file, load_case=self.file.by_id(self.load_case)
)
ifcopenshell.api.structural.remove_structural_load_case(self.file, load_case=self.file.by_id(self.load_case))
return {"FINISHED"}
@@ -600,7 +608,7 @@ class EnableEditingStructuralLoadCase(bpy.types.Operator):
load_case: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
self.props.active_load_case_id = self.load_case
self.props.load_case_editing_type = "ATTRIBUTES"
self.props.load_case_attributes.clear()
@@ -620,7 +628,8 @@ class DisableEditingStructuralLoadCase(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMStructuralProperties.active_load_case_id = 0
props = tool.Structural.get_structural_props()
props.active_load_case_id = 0
return {"FINISHED"}
@@ -631,9 +640,9 @@ class EnableEditingStructuralLoadCaseGroups(bpy.types.Operator):
load_case: bpy.props.IntProperty()
def execute(self, context):
self.props = context.scene.BIMStructuralProperties
self.props.active_load_case_id = self.load_case
self.props.load_case_editing_type = "GROUPS"
props = tool.Structural.get_structural_props()
props.active_load_case_id = self.load_case
props.load_case_editing_type = "GROUPS"
return {"FINISHED"}
@@ -645,10 +654,8 @@ class AddStructuralLoadGroup(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
self.file = tool.Ifc.get()
load_group = ifcopenshell.api.run("structural.add_structural_load_group", self.file)
ifcopenshell.api.run(
"group.assign_group", self.file, products=[load_group], group=self.file.by_id(self.load_case)
)
load_group = ifcopenshell.api.structural.add_structural_load_group(self.file)
ifcopenshell.api.group.assign_group(self.file, products=[load_group], group=self.file.by_id(self.load_case))
return {"FINISHED"}
@@ -660,9 +667,7 @@ class RemoveStructuralLoadGroup(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
self.file = tool.Ifc.get()
ifcopenshell.api.run(
"structural.remove_structural_load_group", self.file, load_group=self.file.by_id(self.load_group)
)
ifcopenshell.api.structural.remove_structural_load_group(self.file, load_group=self.file.by_id(self.load_group))
return {"FINISHED"}
@@ -674,15 +679,15 @@ class EnableEditingStructuralLoadGroupActivities(bpy.types.Operator):
def execute(self, context):
self.file = tool.Ifc.get()
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
self.props.active_load_group_id = self.load_group
self.props.load_group_editing_type = "ACTIVITY"
self.load_structural_activities()
return {"FINISHED"}
def load_structural_activities(self):
def load_structural_activities(self) -> None:
self.props.load_group_activities.clear()
for rel in tool.Ifc.get().by_id(self.load_group).IsGroupedBy:
for rel in self.file.by_id(self.load_group).IsGroupedBy:
for activity in rel.RelatedObjects:
new = self.props.load_group_activities.add()
new.ifc_definition_id = activity.id()
@@ -697,7 +702,7 @@ class AddStructuralActivity(bpy.types.Operator, tool.Ifc.Operator):
load_group: bpy.props.IntProperty()
def _execute(self, context):
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
self.file = tool.Ifc.get()
for obj in context.selected_objects:
element = tool.Ifc.get_entity(obj)
@@ -726,16 +731,13 @@ class AddStructuralActivity(bpy.types.Operator, tool.Ifc.Operator):
ifc_class = applicable_activity_class[element.is_a()]
activity = ifcopenshell.api.run(
"structural.add_structural_activity",
activity = ifcopenshell.api.structural.add_structural_activity(
self.file,
ifc_class=ifc_class,
applied_load=self.file.by_id(int(self.props.applicable_structural_loads)),
structural_member=element,
)
ifcopenshell.api.run(
"group.assign_group", self.file, products=[activity], group=self.file.by_id(self.load_group)
)
ifcopenshell.api.group.assign_group(self.file, products=[activity], group=self.file.by_id(self.load_group))
bpy.ops.bim.enable_editing_structural_load_group_activities(load_group=self.load_group)
return {"FINISHED"}
@@ -747,7 +749,7 @@ class LoadStructuralLoads(bpy.types.Operator):
def execute(self, context):
self.file = tool.Ifc.get()
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
props.structural_loads.clear()
loads = tool.Ifc.get().by_type("IfcStructuralLoad")
if props.filtered_structural_loads:
@@ -780,7 +782,8 @@ class DisableStructuralLoadEditingUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMStructuralProperties.is_editing_loads = False
props = tool.Structural.get_structural_props()
props.is_editing_loads = False
return {"FINISHED"}
@@ -806,7 +809,7 @@ class EnableEditingStructuralLoad(bpy.types.Operator):
structural_load: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
props.structural_load_attributes.clear()
bonsai.bim.helper.import_attributes2(
tool.Ifc.get().by_id(self.structural_load), props.structural_load_attributes
@@ -821,7 +824,8 @@ class DisableEditingStructuralLoad(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMStructuralProperties.active_structural_load_id = 0
props = tool.Structural.get_structural_props()
props.active_structural_load_id = 0
return {"FINISHED"}
@@ -832,12 +836,10 @@ class RemoveStructuralLoad(bpy.types.Operator, tool.Ifc.Operator):
structural_load: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMStructuralProperties
self.file = tool.Ifc.get()
ifcopenshell.api.run(
"structural.remove_structural_load",
ifcopenshell.api.structural.remove_structural_load(
self.file,
**{"structural_load": self.file.by_id(self.structural_load)},
structural_load=self.file.by_id(self.structural_load),
)
bpy.ops.bim.load_structural_loads()
return {"FINISHED"}
@@ -849,16 +851,13 @@ class EditStructuralLoad(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
attributes = bonsai.bim.helper.export_attributes(props.structural_load_attributes)
self.file = tool.Ifc.get()
ifcopenshell.api.run(
"structural.edit_structural_load",
ifcopenshell.api.structural.edit_structural_load(
self.file,
**{
"structural_load": self.file.by_id(props.active_structural_load_id),
"attributes": attributes,
},
structural_load=self.file.by_id(props.active_structural_load_id),
attributes=attributes,
)
bpy.ops.bim.load_structural_loads()
return {"FINISHED"}
@@ -870,7 +869,7 @@ class ToggleFilterStructuralLoads(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
props.filtered_structural_loads = not props.filtered_structural_loads
bpy.ops.bim.load_structural_loads()
return {"FINISHED"}
@@ -883,7 +882,7 @@ class LoadBoundaryConditions(bpy.types.Operator):
def execute(self, context):
self.file = tool.Ifc.get()
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
props.boundary_conditions.clear()
conditions = tool.Ifc.get().by_type("IfcBoundaryCondition")
if props.filtered_boundary_conditions:
@@ -916,7 +915,7 @@ class ToggleFilterBoundaryConditions(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
props.filtered_boundary_conditions = not props.filtered_boundary_conditions
bpy.ops.bim.load_boundary_conditions()
return {"FINISHED"}
@@ -928,7 +927,8 @@ class DisableBoundaryConditionEditingUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMStructuralProperties.is_editing_boundary_conditions = False
props = tool.Structural.get_structural_props()
props.is_editing_boundary_conditions = False
return {"FINISHED"}
@@ -939,8 +939,7 @@ class AddBoundaryCondition(bpy.types.Operator, tool.Ifc.Operator):
ifc_class: bpy.props.StringProperty()
def _execute(self, context):
result = ifcopenshell.api.run(
"structural.add_structural_boundary_condition",
result = ifcopenshell.api.structural.add_structural_boundary_condition(
tool.Ifc.get(),
name="New Load",
ifc_class=self.ifc_class,
@@ -957,7 +956,7 @@ class EnableEditingBoundaryCondition(bpy.types.Operator):
boundary_condition: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
props.boundary_condition_attributes.clear()
boundary_condition = tool.Ifc.get().by_id(self.boundary_condition)
@@ -994,7 +993,8 @@ class DisableEditingBoundaryCondition(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
context.scene.BIMStructuralProperties.active_boundary_condition_id = 0
props = tool.Structural.get_structural_props()
props.active_boundary_condition_id = 0
return {"FINISHED"}
@@ -1005,12 +1005,10 @@ class RemoveBoundaryCondition(bpy.types.Operator, tool.Ifc.Operator):
boundary_condition: bpy.props.IntProperty()
def _execute(self, context):
props = context.scene.BIMStructuralProperties
self.file = tool.Ifc.get()
ifcopenshell.api.run(
"structural.remove_structural_boundary_condition",
ifcopenshell.api.structural.remove_structural_boundary_condition(
self.file,
**{"boundary_condition": self.file.by_id(self.boundary_condition)},
boundary_condition=self.file.by_id(self.boundary_condition),
)
bpy.ops.bim.load_boundary_conditions()
return {"FINISHED"}
@@ -1022,7 +1020,7 @@ class EditBoundaryCondition(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = context.scene.BIMStructuralProperties
props = tool.Structural.get_structural_props()
self.file = tool.Ifc.get()
# attributes = bonsai.bim.helper.export_attributes(props.boundary_condition_attributes)
attributes = {}
@@ -1035,10 +1033,10 @@ class EditBoundaryCondition(bpy.types.Operator, tool.Ifc.Operator):
attributes[attribute.name] = {"value": attribute.bool_value, "type": attribute.enum_value}
else:
attributes[attribute.name] = {"value": attribute.float_value, "type": attribute.enum_value}
ifcopenshell.api.run(
"structural.edit_structural_boundary_condition",
ifcopenshell.api.structural.edit_structural_boundary_condition(
self.file,
**{"condition": self.file.by_id(props.active_boundary_condition_id), "attributes": attributes},
condition=self.file.by_id(props.active_boundary_condition_id),
attributes=attributes,
)
bpy.ops.bim.load_boundary_conditions()
return {"FINISHED"}
@@ -37,52 +37,62 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Union
def get_load_groups_to_show(self, context):
def get_load_groups_to_show(self: "BIMStructuralProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
if not LoadGroupDecorationData.is_loaded:
LoadGroupDecorationData.load()
return LoadGroupDecorationData.data["load_groups_to_show"]
def update_activity_type(self, context):
def update_activity_type(self: "BIMStructuralProperties", context: bpy.types.Context) -> None:
LoadGroupDecorationData.is_loaded = False
def get_applicable_structural_load_types(self, context):
def get_applicable_structural_load_types(
self: "BIMStructuralProperties", context: bpy.types.Context
) -> list[tuple[str, str, str]]:
if not StructuralLoadCasesData.is_loaded:
StructuralLoadCasesData.load()
return StructuralLoadCasesData.data["applicable_structural_load_types"]
def updateApplicableStructuralLoadTypes(self, context):
def updateApplicableStructuralLoadTypes(self: "BIMStructuralProperties", context: bpy.types.Context) -> None:
StructuralLoadCasesData.data["applicable_structural_load_types"] = (
StructuralLoadCasesData.applicable_structural_load_types()
)
def get_applicable_structural_loads(self, context):
def get_applicable_structural_loads(
self: "BIMStructuralProperties", context: bpy.types.Context
) -> list[tuple[str, str, str]]:
if not StructuralLoadCasesData.is_loaded:
StructuralLoadCasesData.load()
return StructuralLoadCasesData.data["applicable_structural_loads"]
def get_structural_load_types(self, context):
def get_structural_load_types(
self: "BIMStructuralProperties", context: bpy.types.Context
) -> list[tuple[str, str, str]]:
if not StructuralLoadsData.is_loaded:
StructuralLoadsData.load()
return StructuralLoadsData.data["structural_load_types"]
def get_boundary_condition_types(self, context):
def get_boundary_condition_types(
self: "BIMStructuralProperties", context: bpy.types.Context
) -> list[tuple[str, str, str]]:
if not BoundaryConditionsData.is_loaded:
BoundaryConditionsData.load()
return BoundaryConditionsData.data["boundary_condition_types"]
def updateAxisAngle(self, context):
def updateAxisAngle(self: "BIMObjectStructuralProperties", context: bpy.types.Context) -> None:
if not self.axis_empty:
return
obj = context.active_object
assert obj and isinstance(obj.data, bpy.types.Mesh)
empty = self.axis_empty
x_axis = obj.data.vertices[1].co - obj.data.vertices[0].co
empty.location = obj.data.vertices[0].co
@@ -92,10 +102,11 @@ def updateAxisAngle(self, context):
empty.rotation_euler[0] = radians(self.axis_angle)
def updateConnectionCS(self, context):
def updateConnectionCS(self: "BIMObjectStructuralProperties", context: bpy.types.Context) -> None:
if not self.ccs_empty:
return
obj = context.active_object
assert obj and isinstance(obj.data, bpy.types.Mesh)
empty = self.ccs_empty
empty.location = obj.data.vertices[0].co
empty.rotation_mode = "XYZ"
@@ -108,24 +119,39 @@ class StructuralAnalysisModel(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
if TYPE_CHECKING:
ifc_definition_id: int
class StructuralActivity(PropertyGroup):
name: StringProperty(name="Name")
applied_load_class: StringProperty(name="Applied Load Class")
ifc_definition_id: IntProperty(name="IFC Definition ID")
if TYPE_CHECKING:
applied_load_class: str
ifc_definition_id: int
class StructuralLoad(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
number_of_inverse_references: IntProperty(name="Number of Inverse References")
if TYPE_CHECKING:
ifc_definition_id: int
number_of_inverse_references: int
class BoundaryCondition(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
number_of_inverse_references: IntProperty(name="Number of Inverse References")
if TYPE_CHECKING:
ifc_definition_id: int
number_of_inverse_references: int
class BIMStructuralProperties(PropertyGroup):
structural_analysis_model_attributes: CollectionProperty(
@@ -187,6 +213,45 @@ class BIMStructuralProperties(PropertyGroup):
)
load_group_to_show: EnumProperty(items=get_load_groups_to_show, name="Load Groups")
if TYPE_CHECKING:
structural_analysis_model_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
is_editing: bool
structural_analysis_models: bpy.types.bpy_prop_collection_idprop[StructuralAnalysisModel]
active_structural_analysis_model_index: int
active_structural_analysis_model_id: int
load_case_editing_type: str
load_case_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
active_load_case_id: int
load_group_editing_type: str
active_load_group_id: int
applicable_structural_load_types: str
applicable_structural_loads: str
load_group_activities: bpy.types.bpy_prop_collection_idprop[StructuralActivity]
active_load_group_activity_index: int
structural_loads: bpy.types.bpy_prop_collection_idprop[StructuralLoad]
active_structural_load_index: int
active_structural_load_id: int
is_editing_loads: bool
structural_load_types: str
structural_load_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
filtered_structural_loads: bool
boundary_conditions: bpy.types.bpy_prop_collection_idprop[BoundaryCondition]
active_boundary_condition_index: int
active_boundary_condition_id: int
is_editing_boundary_conditions: bool
boundary_condition_types: str
boundary_condition_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
filtered_boundary_conditions: bool
show_loads: bool
update_load_repr: bool
enable_repr_auto_update: bool
reference_frame: str
activity_type: str
load_group_to_show: str
class BIMObjectStructuralProperties(PropertyGroup):
boundary_condition_attributes: CollectionProperty(name="Boundary Condition Attributes", type=Attribute)
@@ -203,3 +268,19 @@ class BIMObjectStructuralProperties(PropertyGroup):
ccs_y_angle: FloatProperty(name="Connection CS Y Angle", update=updateConnectionCS)
ccs_z_angle: FloatProperty(name="Connection CS Z Angle", update=updateConnectionCS)
ccs_empty: PointerProperty(name="CCS Empty", type=bpy.types.Object)
if TYPE_CHECKING:
boundary_condition_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
active_boundary_condition: int
active_connects_structural_member: int
relating_structural_member: Union[bpy.types.Object, None]
is_editing_axis: bool
axis_angle: float
axis_empty: Union[bpy.types.Object, None]
# relating_structural_activity: Union[bpy.types.Object, None]
is_editing_connection_cs: bool
ccs_x_angle: float
ccs_y_angle: float
ccs_z_angle: float
ccs_empty: Union[bpy.types.Object, None]
+87 -23
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.tool as tool
import bonsai.bim.helper
@@ -31,9 +32,25 @@ from bonsai.bim.module.structural.data import (
StructuralConnectionData,
BoundaryConditionsData,
)
from typing import TYPE_CHECKING, Any, Union
if TYPE_CHECKING:
from bonsai.bim.module.structural.prop import (
BIMStructuralProperties,
BIMObjectStructuralProperties,
BoundaryCondition,
StructuralLoad,
StructuralActivity,
StructuralAnalysisModel,
)
def draw_boundary_condition_ui(layout, boundary_condition, connection_id, props):
def draw_boundary_condition_ui(
layout: bpy.types.UILayout,
boundary_condition: dict[str, Any],
connection_id: int,
props: BIMObjectStructuralProperties,
) -> None:
row = layout.row(align=True)
if not boundary_condition:
row.label(text="No Boundary Condition Found", icon="CON_TRACKTO")
@@ -59,11 +76,13 @@ def draw_boundary_condition_ui(layout, boundary_condition, connection_id, props)
draw_boundary_condition_read_only_ui(layout, boundary_condition)
def draw_boundary_condition_editable_ui(layout: bpy.types.UILayout, props: bpy.types.PropertyGroup) -> None:
def draw_boundary_condition_editable_ui(
layout: bpy.types.UILayout, props: Union[BIMStructuralProperties, BIMObjectStructuralProperties]
) -> None:
draw_attributes(props.boundary_condition_attributes, layout)
def draw_boundary_condition_read_only_ui(layout, boundary_condition):
def draw_boundary_condition_read_only_ui(layout: bpy.types.UILayout, boundary_condition: dict[str, Any]) -> None:
for attribute in boundary_condition["attributes"]:
row = layout.row(align=True)
row.label(text=attribute["name"])
@@ -100,11 +119,15 @@ class BIM_PT_structural_boundary_conditions(Panel):
if not StructuralBoundaryConditionsData.is_loaded:
StructuralBoundaryConditionsData.load()
obj = context.active_object
assert obj
self.props = tool.Structural.get_object_structural_props(obj)
draw_boundary_condition_ui(
self.layout,
StructuralBoundaryConditionsData.data["boundary_condition"],
StructuralBoundaryConditionsData.data["connection_id"],
context.active_object.BIMStructuralProperties,
self.props,
)
@@ -135,7 +158,9 @@ class BIM_PT_connected_structural_members(Panel):
if not ConnectedStructuralMembersData.is_loaded:
ConnectedStructuralMembersData.load()
self.props = context.active_object.BIMStructuralProperties
obj = context.active_object
assert obj
self.props = tool.Structural.get_object_structural_props(obj)
row = self.layout.row(align=True)
row.prop(self.props, "relating_structural_member", text="", icon="CON_TRACKTO")
@@ -188,7 +213,9 @@ class BIM_PT_structural_member(Panel):
if not StructuralMemberData.is_loaded:
StructuralMemberData.load()
self.props = context.active_object.BIMStructuralProperties
obj = context.active_object
assert obj
self.props = tool.Structural.get_object_structural_props(obj)
if StructuralMemberData.data["active_object_class"] == "IfcStructuralCurveMember":
if self.props.is_editing_axis:
@@ -231,7 +258,9 @@ class BIM_PT_structural_connection(Panel):
if not StructuralConnectionData.is_loaded:
StructuralConnectionData.load()
self.props = context.active_object.BIMStructuralProperties
obj = context.active_object
assert obj
self.props = tool.Structural.get_object_structural_props(obj)
if StructuralConnectionData.data["active_object_class"] == "IfcStructuralCurveConnection":
if self.props.is_editing_axis:
@@ -281,7 +310,7 @@ class BIM_PT_structural_analysis_models(Panel):
if not StructuralAnalysisModelsData.is_loaded:
StructuralAnalysisModelsData.load()
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
row = self.layout.row(align=True)
row.label(
@@ -309,7 +338,16 @@ class BIM_PT_structural_analysis_models(Panel):
class BIM_UL_structural_analysis_models(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context: bpy.types.Context,
layout: bpy.types.UILayout,
data: BIMStructuralProperties,
item: StructuralAnalysisModel,
icon,
active_data,
active_propname,
):
if item:
row = layout.row(align=True)
row.label(text=item.name)
@@ -324,10 +362,10 @@ class BIM_UL_structural_analysis_models(UIList):
op = row.operator("bim.assign_structural_analysis_model", text="", icon="KEYFRAME", emboss=False)
op.structural_analysis_model = item.ifc_definition_id
if context.scene.BIMStructuralProperties.active_structural_analysis_model_id == item.ifc_definition_id:
if data.active_structural_analysis_model_id == item.ifc_definition_id:
row.operator("bim.edit_structural_analysis_model", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_structural_analysis_model", text="", icon="CANCEL")
elif context.scene.BIMStructuralProperties.active_structural_analysis_model_id:
elif data.active_structural_analysis_model_id:
op = row.operator("bim.remove_structural_analysis_model", text="", icon="X")
op.structural_analysis_model = item.ifc_definition_id
else:
@@ -354,7 +392,7 @@ class BIM_PT_structural_load_cases(Panel):
if not StructuralLoadCasesData.is_loaded:
StructuralLoadCasesData.load()
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
row = self.layout.row()
row.operator("bim.add_structural_load_case", icon="ADD")
@@ -425,7 +463,16 @@ class BIM_PT_structural_load_cases(Panel):
class BIM_UL_structural_activities(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMStructuralProperties,
item: StructuralActivity,
icon,
active_data,
active_propname,
):
if item:
row = layout.row(align=True)
row.label(text=item.name)
@@ -446,8 +493,7 @@ class BIM_PT_show_structural_activities(Panel):
return file and hasattr(file, "schema") and file.schema != "IFC2X3"
def draw(self, context):
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
row = self.layout.row(align=True)
row.operator(
@@ -480,7 +526,7 @@ class BIM_PT_structural_loads(Panel):
if not StructuralLoadsData.is_loaded:
StructuralLoadsData.load()
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
row = self.layout.row(align=True)
row.label(text=f"{StructuralLoadsData.data['total_loads']} Structural Loads Found", icon="ANIM_DATA")
@@ -513,16 +559,25 @@ class BIM_PT_structural_loads(Panel):
class BIM_UL_structural_loads(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMStructuralProperties,
item: StructuralLoad,
icon,
active_data,
active_propname,
):
if item:
row = layout.row(align=True)
row.label(text=f"{item.name} ({item.number_of_inverse_references})")
row.label(text=StructuralLoadsData.data["load_classes"][item.ifc_definition_id])
if context.scene.BIMStructuralProperties.active_structural_load_id == item.ifc_definition_id:
if data.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:
elif data.active_structural_load_id:
op = row.operator("bim.remove_structural_load", text="", icon="X")
op.structural_load = item.ifc_definition_id
else:
@@ -549,7 +604,7 @@ class BIM_PT_boundary_conditions(Panel):
if not BoundaryConditionsData.is_loaded:
BoundaryConditionsData.load()
self.props = context.scene.BIMStructuralProperties
self.props = tool.Structural.get_structural_props()
row = self.layout.row(align=True)
row.label(
@@ -587,16 +642,25 @@ class BIM_PT_boundary_conditions(Panel):
class BIM_UL_boundary_conditions(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMStructuralProperties,
item: BoundaryCondition,
icon,
active_data,
active_propname,
):
if item:
row = layout.row(align=True)
row.label(text=f"{item.name} ({item.number_of_inverse_references})")
row.label(text=BoundaryConditionsData.data["condition_classes"][item.ifc_definition_id])
if context.scene.BIMStructuralProperties.active_boundary_condition_id == item.ifc_definition_id:
if data.active_boundary_condition_id == item.ifc_definition_id:
row.operator("bim.edit_boundary_condition", text="", icon="CHECKMARK")
row.operator("bim.disable_editing_boundary_condition", text="", icon="CANCEL")
elif context.scene.BIMStructuralProperties.active_boundary_condition_id:
elif data.active_boundary_condition_id:
op = row.operator("bim.remove_boundary_condition", text="", icon="X")
op.boundary_condition = item.ifc_definition_id
else:
@@ -54,7 +54,7 @@ class StructuralToolUI:
@classmethod
def draw(cls, context, layout):
cls.layout = layout
# cls.props = context.scene.BIMStructuralProperties
cls.props = tool.Structural.get_structural_props()
row = cls.layout.row(align=True)
if not tool.Ifc.get():
@@ -99,12 +99,12 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
return operator.description or ""
def _execute(self, context):
# self.props = context.scene.BIMStructuralProperties
# self.props = tool.Structural.get_structural_props()
getattr(self, f"hotkey_{self.hotkey}")()
def invoke(self, context, event):
# https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey
# self.props = context.scene.BIMStructuralProperties
# self.props = tool.Structural.get_structural_props()
return self.execute(context)
def draw(self, context):
+11 -2
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.core.tool
import bonsai.bim.schema
@@ -24,12 +25,19 @@ import ifcopenshell
import ifcopenshell.util.unit
import ifcopenshell.util.element
from mathutils import Vector
from typing import Optional, Union, Literal
from typing import Optional, Union, Literal, TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.qto.prop import BIMQtoProperties
QuantityTypes = Literal["Q_LENGTH", "Q_AREA", "Q_VOLUME"]
class Qto(bonsai.core.tool.Qto):
@classmethod
def get_qto_props(cls) -> BIMQtoProperties:
return bpy.context.scene.BIMQtoProperties
@classmethod
def get_radius_of_selected_vertices(cls, obj: bpy.types.Object) -> float:
selected_verts = [v.co for v in obj.data.vertices if v.select]
@@ -41,7 +49,8 @@ class Qto(bonsai.core.tool.Qto):
@classmethod
def set_qto_result(cls, result: float) -> None:
bpy.context.scene.BIMQtoProperties.qto_result = str(round(result, 3))
props = cls.get_qto_props()
props.qto_result = str(round(result, 3))
@classmethod
def get_rounded_value(cls, new_quantity: float) -> float:
+27 -10
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import ifcopenshell
import ifcopenshell.util.representation
@@ -23,30 +24,46 @@ import json
import bonsai.bim.helper
import bonsai.core.tool
import bonsai.tool as tool
from typing import Union, Any
from typing import Union, Any, TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.structural.prop import BIMStructuralProperties, BIMObjectStructuralProperties
class Structural(bonsai.core.tool.Structural):
@classmethod
def get_structural_props(cls) -> BIMStructuralProperties:
return bpy.context.scene.BIMStructuralProperties
@classmethod
def get_object_structural_props(cls, obj: bpy.types.Object) -> BIMObjectStructuralProperties:
return obj.BIMStructuralProperties
@classmethod
def disable_editing_structural_analysis_model(cls) -> None:
bpy.context.scene.BIMStructuralProperties.active_structural_analysis_model_id = 0
props = cls.get_structural_props()
props.active_structural_analysis_model_id = 0
@classmethod
def disable_structural_analysis_model_editing_ui(cls) -> None:
bpy.context.scene.BIMStructuralProperties.is_editing = False
props = cls.get_structural_props()
props.is_editing = False
@classmethod
def enable_editing_structural_analysis_model(cls, model: Union[int, None]) -> None:
if model:
bpy.context.scene.BIMStructuralProperties.active_structural_analysis_model_id = model
props = cls.get_structural_props()
props.active_structural_analysis_model_id = model
@classmethod
def enable_structural_analysis_model_editing_ui(cls) -> None:
bpy.context.scene.BIMStructuralProperties.is_editing = True
props = cls.get_structural_props()
props.is_editing = True
@classmethod
def enabled_structural_analysis_model_editing_ui(cls) -> bool:
return bpy.context.scene.BIMStructuralProperties.is_editing
props = cls.get_structural_props()
return props.is_editing
@classmethod
def ensure_representation_contexts(cls) -> None:
@@ -71,7 +88,7 @@ class Structural(bonsai.core.tool.Structural):
@classmethod
def get_active_structural_analysis_model(cls) -> ifcopenshell.entity_instance:
props = bpy.context.scene.BIMStructuralProperties
props = cls.get_structural_props()
model = tool.Ifc.get().by_id(props.active_structural_analysis_model_id)
return model
@@ -120,13 +137,13 @@ class Structural(bonsai.core.tool.Structural):
@classmethod
def get_structural_analysis_model_attributes(cls) -> dict[str, Any]:
props = bpy.context.scene.BIMStructuralProperties
props = cls.get_structural_props()
attributes = bonsai.bim.helper.export_attributes(props.structural_analysis_model_attributes)
return attributes
@classmethod
def load_structural_analysis_model_attributes(cls, data: dict[str, Any]) -> None:
props = bpy.context.scene.BIMStructuralProperties
props = cls.get_structural_props()
props.structural_analysis_model_attributes.clear()
schema = tool.Ifc.schema()
for attribute in schema.declaration_by_name("IfcStructuralAnalysisModel").all_attributes():
@@ -149,7 +166,7 @@ class Structural(bonsai.core.tool.Structural):
@classmethod
def load_structural_analysis_models(cls) -> None:
models = tool.Structural.get_ifc_structural_analysis_models()
props = bpy.context.scene.BIMStructuralProperties
props = cls.get_structural_props()
props.structural_analysis_models.clear()
for ifc_definition_id, model in models.items():
new = props.structural_analysis_models.add()
+2 -1
View File
@@ -42,7 +42,8 @@ class TestGetRadiusOfSelectedVertices(test.bim.bootstrap.NewFile):
class TestSetQtoResult(test.bim.bootstrap.NewFile):
def test_run(self):
subject.set_qto_result(123.4567)
assert bpy.context.scene.BIMQtoProperties.qto_result == "123.457"
props = tool.Qto.get_qto_props()
assert props.qto_result == "123.457"
class TestGetRoundedValue(test.bim.bootstrap.NewFile):