diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py index de8cea8a95..5bc6de9b6f 100644 --- a/src/bonsai/bonsai/bim/module/pset/ui.py +++ b/src/bonsai/bonsai/bim/module/pset/ui.py @@ -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. diff --git a/src/bonsai/bonsai/bim/module/qto/calculator.py b/src/bonsai/bonsai/bim/module/qto/calculator.py index 38bc8ca423..1cfd731bb3 100644 --- a/src/bonsai/bonsai/bim/module/qto/calculator.py +++ b/src/bonsai/bonsai/bim/module/qto/calculator.py @@ -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) diff --git a/src/bonsai/bonsai/bim/module/qto/helper.py b/src/bonsai/bonsai/bim/module/qto/helper.py index 47fd42642e..a796d0a164 100644 --- a/src/bonsai/bonsai/bim/module/qto/helper.py +++ b/src/bonsai/bonsai/bim/module/qto/helper.py @@ -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) diff --git a/src/bonsai/bonsai/bim/module/qto/operator.py b/src/bonsai/bonsai/bim/module/qto/operator.py index 8a996fc383..0f4c706dbd 100644 --- a/src/bonsai/bonsai/bim/module/qto/operator.py +++ b/src/bonsai/bonsai/bim/module/qto/operator.py @@ -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: diff --git a/src/bonsai/bonsai/bim/module/qto/prop.py b/src/bonsai/bonsai/bim/module/qto/prop.py index 0a73240e64..fa90ba6f27 100644 --- a/src/bonsai/bonsai/bim/module/qto/prop.py +++ b/src/bonsai/bonsai/bim/module/qto/prop.py @@ -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 diff --git a/src/bonsai/bonsai/bim/module/qto/ui.py b/src/bonsai/bonsai/bim/module/qto/ui.py index 49840ba4be..4762062799 100644 --- a/src/bonsai/bonsai/bim/module/qto/ui.py +++ b/src/bonsai/bonsai/bim/module/qto/ui.py @@ -17,6 +17,7 @@ # along with Bonsai. If not, see . 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") diff --git a/src/bonsai/bonsai/bim/module/structural/data.py b/src/bonsai/bonsai/bim/module/structural/data.py index 5c98eadbe8..d2cf1f3fbd 100644 --- a/src/bonsai/bonsai/bim/module/structural/data.py +++ b/src/bonsai/bonsai/bim/module/structural/data.py @@ -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): diff --git a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py index a91a7947c5..f3e7f267cb 100644 --- a/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py +++ b/src/bonsai/bonsai/bim/module/structural/load_decoration_data.py @@ -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 diff --git a/src/bonsai/bonsai/bim/module/structural/operator.py b/src/bonsai/bonsai/bim/module/structural/operator.py index c483e9d236..92b88a78ec 100644 --- a/src/bonsai/bonsai/bim/module/structural/operator.py +++ b/src/bonsai/bonsai/bim/module/structural/operator.py @@ -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"} diff --git a/src/bonsai/bonsai/bim/module/structural/prop.py b/src/bonsai/bonsai/bim/module/structural/prop.py index 2ecc29834a..c0db44fac6 100644 --- a/src/bonsai/bonsai/bim/module/structural/prop.py +++ b/src/bonsai/bonsai/bim/module/structural/prop.py @@ -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] diff --git a/src/bonsai/bonsai/bim/module/structural/ui.py b/src/bonsai/bonsai/bim/module/structural/ui.py index 1e4ceee997..ea359e4ca2 100644 --- a/src/bonsai/bonsai/bim/module/structural/ui.py +++ b/src/bonsai/bonsai/bim/module/structural/ui.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +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: diff --git a/src/bonsai/bonsai/bim/module/structural/workspace.py b/src/bonsai/bonsai/bim/module/structural/workspace.py index bb02867af1..fbacac3e1a 100644 --- a/src/bonsai/bonsai/bim/module/structural/workspace.py +++ b/src/bonsai/bonsai/bim/module/structural/workspace.py @@ -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): diff --git a/src/bonsai/bonsai/tool/qto.py b/src/bonsai/bonsai/tool/qto.py index 803a00e560..4a17be291b 100644 --- a/src/bonsai/bonsai/tool/qto.py +++ b/src/bonsai/bonsai/tool/qto.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +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: diff --git a/src/bonsai/bonsai/tool/structural.py b/src/bonsai/bonsai/tool/structural.py index 5796bf6f44..54c73ca537 100644 --- a/src/bonsai/bonsai/tool/structural.py +++ b/src/bonsai/bonsai/tool/structural.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Bonsai. If not, see . +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() diff --git a/src/bonsai/test/tool/test_qto.py b/src/bonsai/test/tool/test_qto.py index b9e3926f65..7ab26cd9d8 100644 --- a/src/bonsai/test/tool/test_qto.py +++ b/src/bonsai/test/tool/test_qto.py @@ -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): diff --git a/src/ifc5d/ifc5d/qto.py b/src/ifc5d/ifc5d/qto.py index 3766be8d0d..8827bef51e 100644 --- a/src/ifc5d/ifc5d/qto.py +++ b/src/ifc5d/ifc5d/qto.py @@ -30,11 +30,16 @@ import ifcopenshell.util.shape import ifcopenshell.util.representation import ifcopenshell.util.type import multiprocessing -from collections import namedtuple, defaultdict -from typing import Any, Literal, get_args, Union, Iterable +from collections import defaultdict +from typing import Any, Literal, get_args, Union, Iterable, NamedTuple + + +class Function(NamedTuple): + measure: str + name: str + description: str -Function = namedtuple("Function", ["measure", "name", "description"]) RULE_SET = Literal[ "IFC4QtoBaseQuantities", "IFC4QtoBaseQuantitiesBlender", @@ -161,7 +166,23 @@ class IteratorForTypes: return True -class IfcOpenShell: +class QtoCalculator: + """Abstract class for Qto calculators.""" + + functions: dict[str, Function] + + @classmethod + def calculate( + cls, + ifc_file: ifcopenshell.file, + elements: set[ifcopenshell.entity_instance], + qtos: dict[str, dict[str, Union[str, None]]], + results: ResultsDict, + ) -> None: + raise NotImplementedError + + +class IfcOpenShell(QtoCalculator): """Calculates Model body context geometry using the default IfcOpenShell iterator on triangulation elements.""" @@ -221,13 +242,7 @@ class IfcOpenShell: functions[f"net_{k}"] = Function(v.measure, f"Net {v.name}", v.description) @classmethod - def calculate( - cls, - ifc_file: ifcopenshell.file, - elements: set[ifcopenshell.entity_instance], - qtos: dict[str, dict[str, Union[str, None]]], - results: ResultsDict, - ) -> None: + def calculate(cls, ifc_file, elements, qtos, results): formula_functions: dict[str, types.FunctionType] = {} cls.gross_settings = ifcopenshell.geom.settings() @@ -327,9 +342,10 @@ class IfcOpenShell: return max([x, y, z]) -class Blender: +class Blender(QtoCalculator): """Calculates geometry based on currently loaded Blender objects.""" + # Implementations are located in bonsai.bim.module.qto.calculator. functions = { # IfcLengthMeasure "get_covering_width": Function("IfcLengthMeasure", "Covering Width", ""), @@ -372,13 +388,8 @@ class Blender: "get_net_weight": Function("IfcMassMeasure", "Net Weight", ""), } - @staticmethod - def calculate( - ifc_file: ifcopenshell.file, - elements: set[ifcopenshell.entity_instance], - qtos: dict[str, dict[str, Union[str, None]]], - results: ResultsDict, - ) -> None: + @classmethod + def calculate(cls, ifc_file, elements, qtos, results): import bonsai.tool as tool import bonsai.bim.module.qto.calculator as calculator @@ -406,4 +417,7 @@ class Blender: results[element] = element_results -calculators = {"Blender": Blender, "IfcOpenShell": IfcOpenShell} +calculators: dict[str, type[QtoCalculator]] = { + "Blender": Blender, + "IfcOpenShell": IfcOpenShell, +} diff --git a/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py b/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py index dac156daea..b03f003594 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py +++ b/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py @@ -64,13 +64,10 @@ def assign_object( :param products: The list of parts of the aggregate, typically of IfcElement or IfcSpatialStructureElement subclass - :type product: list[ifcopenshell.entity_instance] :param relating_object: The whole of the aggregate, typically an IfcElement or IfcSpatialStructureElement subclass - :type relating_object: ifcopenshell.entity_instance :return: The IfcRelAggregate relationship instance or `None` if `products` was empty list. - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -86,16 +83,10 @@ def assign_object( # The site has a building ifcopenshell.api.aggregate.assign_object(model, products=[subelement], relating_object=element) """ - settings = { - "products": products, - "relating_object": relating_object, - } - - if not settings["products"]: + if not products: return - products = set(settings["products"]) - relating_object = settings["relating_object"] + products_set = set(products) is_decomposed_by = next((i for i in relating_object.IsDecomposedBy if i.is_a("IfcRelAggregates")), None) previous_aggregates_rels: set[ifcopenshell.entity_instance] = set() @@ -103,7 +94,7 @@ def assign_object( products_with_aggregates: list[ifcopenshell.entity_instance] = [] # check if there is anything to change - for product in products: + for product in products_set: product_rel = next(iter(product.Decomposes), None) if product_rel is None: @@ -129,7 +120,7 @@ def assign_object( # unassign elements from previous aggregates for decomposes in previous_aggregates_rels: - related_objects = set(decomposes.RelatedObjects) - products + related_objects = set(decomposes.RelatedObjects) - products_set if related_objects: decomposes.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(file, **{"element": decomposes}) @@ -141,7 +132,7 @@ def assign_object( # assign elements to a new aggregate if is_decomposed_by: - is_decomposed_by.RelatedObjects = list(set(is_decomposed_by.RelatedObjects) | products) + is_decomposed_by.RelatedObjects = list(set(is_decomposed_by.RelatedObjects) | products_set) ifcopenshell.api.owner.update_owner_history(file, **{"element": is_decomposed_by}) else: is_decomposed_by = file.create_entity( @@ -149,7 +140,7 @@ def assign_object( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": list(products), + "RelatedObjects": list(products_set), "RelatingObject": relating_object, } ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/boundary/copy_boundary.py b/src/ifcopenshell-python/ifcopenshell/api/boundary/copy_boundary.py index af2bc72cb2..a2e74b5a11 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/boundary/copy_boundary.py +++ b/src/ifcopenshell-python/ifcopenshell/api/boundary/copy_boundary.py @@ -23,9 +23,7 @@ def copy_boundary(file: ifcopenshell.file, boundary: ifcopenshell.entity_instanc """Copies a space boundary :param boundary: The IfcRelSpaceBoundary you want to copy. - :type boundary: ifcopenshell.entity_instance :return: Duplicate of the IfcRelSpaceBoundary - :rtype: ifcopenshell.entity_instance Example: @@ -36,9 +34,7 @@ def copy_boundary(file: ifcopenshell.file, boundary: ifcopenshell.entity_instanc # And now we have two boundary_copy = ifcopenshell.api.boundary.copy_boundary(model, boundary=boundary) """ - settings = {"boundary": boundary} - - result = ifcopenshell.util.element.copy(file, settings["boundary"]) + result = ifcopenshell.util.element.copy(file, boundary) if result.ConnectionGeometry: result.ConnectionGeometry = ifcopenshell.util.element.copy_deep(file, result.ConnectionGeometry) return result diff --git a/src/ifcopenshell-python/ifcopenshell/api/boundary/remove_boundary.py b/src/ifcopenshell-python/ifcopenshell/api/boundary/remove_boundary.py index 13dfb7ab6b..4aadabcbce 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/boundary/remove_boundary.py +++ b/src/ifcopenshell-python/ifcopenshell/api/boundary/remove_boundary.py @@ -27,9 +27,7 @@ def remove_boundary(file: ifcopenshell.file, boundary: ifcopenshell.entity_insta boundary and its connection geometry is removed. :param boundary: The IfcRelSpaceBoundary you want to remove. - :type boundary: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -40,13 +38,11 @@ def remove_boundary(file: ifcopenshell.file, boundary: ifcopenshell.entity_insta # Let's remove it! ifcopenshell.api.boundary.remove_boundary(model, boundary=boundary) """ - settings = {"boundary": boundary} - - geometry = settings["boundary"].ConnectionGeometry + geometry = boundary.ConnectionGeometry if geometry: - settings["boundary"].ConnectionGeometry = None + boundary.ConnectionGeometry = None ifcopenshell.util.element.remove_deep2(file, geometry) - history = settings["boundary"].OwnerHistory - file.remove(settings["boundary"]) + history = boundary.OwnerHistory + file.remove(boundary) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/constraint/add_metric.py b/src/ifcopenshell-python/ifcopenshell/api/constraint/add_metric.py index f1fcf20a0e..001c86a540 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/constraint/add_metric.py +++ b/src/ifcopenshell-python/ifcopenshell/api/constraint/add_metric.py @@ -28,9 +28,7 @@ def add_metric(file: ifcopenshell.file, objective: ifcopenshell.entity_instance) to meet the objective of the constraint. :param objective: The IfcObjective that this metric is a benchmark of. - :type objective: ifcopenshell.entity_instance :return: The newly created IfcMetric entity - :rtype: ifcopenshell.entity_instance Example: @@ -40,10 +38,6 @@ def add_metric(file: ifcopenshell.file, objective: ifcopenshell.entity_instance) metric = ifcopenshell.api.constraint.add_metric(model, objective=objective) """ - settings = { - "objective": objective, - } - metric = file.create_entity( "IfcMetric", **{ @@ -52,8 +46,9 @@ def add_metric(file: ifcopenshell.file, objective: ifcopenshell.entity_instance) "Benchmark": "EQUALTO", }, ) - if settings["objective"]: - benchmark_values = list(settings["objective"].BenchmarkValues or []) + if objective: + benchmark_values: list[ifcopenshell.entity_instance] + benchmark_values = list(objective.BenchmarkValues or []) benchmark_values.append(metric) - settings["objective"].BenchmarkValues = benchmark_values + objective.BenchmarkValues = benchmark_values return metric diff --git a/src/ifcopenshell-python/ifcopenshell/api/constraint/add_objective.py b/src/ifcopenshell-python/ifcopenshell/api/constraint/add_objective.py index 064648f1b7..4c434a9edf 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/constraint/add_objective.py +++ b/src/ifcopenshell-python/ifcopenshell/api/constraint/add_objective.py @@ -29,7 +29,6 @@ def add_objective(file: ifcopenshell.file) -> ifcopenshell.entity_instance: quantities. See ifcopenshell.api.constraint.add_metric for more information. :return: The newly created IfcObjective entity - :rtype: ifcopenshell.entity_instance Example: @@ -42,8 +41,6 @@ def add_objective(file: ifcopenshell.file) -> ifcopenshell.entity_instance: # Note: the objective right now is purely qualitative and for # information purposes. You may wish to add quantiative metrics. """ - settings = {} - return file.create_entity( "IfcObjective", **{"Name": "Unnamed", "ConstraintGrade": "NOTDEFINED", "ObjectiveQualifier": "NOTDEFINED"} ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/constraint/remove_constraint.py b/src/ifcopenshell-python/ifcopenshell/api/constraint/remove_constraint.py index 381a9e191e..c98f08ade7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/constraint/remove_constraint.py +++ b/src/ifcopenshell-python/ifcopenshell/api/constraint/remove_constraint.py @@ -41,9 +41,7 @@ def remove_constraint(file: ifcopenshell.file, constraint: ifcopenshell.entity_i ifcopenshell.api.constraint.remove_constraint(model, constraint=objective) """ - settings = {"constraint": constraint} - - file.remove(settings["constraint"]) + file.remove(constraint) for rel in file.by_type("IfcRelAssociatesConstraint"): if not rel.RelatingConstraint: history = rel.OwnerHistory diff --git a/src/ifcopenshell-python/ifcopenshell/api/context/remove_context.py b/src/ifcopenshell-python/ifcopenshell/api/context/remove_context.py index 2d6defeaf3..7fee232456 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/context/remove_context.py +++ b/src/ifcopenshell-python/ifcopenshell/api/context/remove_context.py @@ -29,9 +29,7 @@ def remove_context(file: ifcopenshell.file, context: ifcopenshell.entity_instanc removed. If a context is removed, then any subcontexts are also removed. :param context: The IfcGeometricRepresentationContext entity to remove - :type context: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -46,22 +44,20 @@ def remove_context(file: ifcopenshell.file, context: ifcopenshell.entity_instanc # Let's just get rid of it completely ifcopenshell.api.context.remove_context(model, context=body) """ - settings = {"context": context} - - for subcontext in settings["context"].HasSubContexts: + for subcontext in context.HasSubContexts: ifcopenshell.api.context.remove_context(file, context=subcontext) - if getattr(settings["context"], "ParentContext", None): - new = settings["context"].ParentContext - for inverse in file.get_inverse(settings["context"]): + if getattr(context, "ParentContext", None): + new = context.ParentContext + for inverse in file.get_inverse(context): if inverse.is_a("IfcCoordinateOperation"): inverse.SourceCRS = inverse.TargetCRS ifcopenshell.util.element.remove_deep(file, inverse) else: - ifcopenshell.util.element.replace_attribute(inverse, settings["context"], new) - file.remove(settings["context"]) + ifcopenshell.util.element.replace_attribute(inverse, context, new) + file.remove(context) else: - representations_in_context = settings["context"].RepresentationsInContext - file.remove(settings["context"]) + representations_in_context = context.RepresentationsInContext + file.remove(context) for element in representations_in_context: ifcopenshell.api.geometry.remove_representation(file, representation=element) diff --git a/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py b/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py index 303cfa6726..2a3ad405f2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py +++ b/src/ifcopenshell-python/ifcopenshell/api/control/assign_control.py @@ -42,12 +42,9 @@ def assign_control( :param relating_control: The IfcControl entity that is creating the control or constraint - :type relating_control: ifcopenshell.entity_instance :param related_object: The IfcObjectDefinition that is being controlled - :type related_object: ifcopenshell.entity_instance :return: The newly created IfcRelAssignsToControl. If relationship already existed before and wasn't changed then returns None. - :rtype: ifcopenshell.entity_instance, None Example: @@ -72,25 +69,20 @@ def assign_control( ifcopenshell.api.control.assign_control(model, relating_control=cost_item, related_object=wall) """ - settings = { - "relating_control": relating_control, - "related_object": related_object, - } - - if settings["related_object"].HasAssignments: - for assignment in settings["related_object"].HasAssignments: - if assignment.is_a("IfcRelAssignsToControl") and assignment.RelatingControl == settings["relating_control"]: + if related_object.HasAssignments: + for assignment in related_object.HasAssignments: + if assignment.is_a("IfcRelAssignsToControl") and assignment.RelatingControl == relating_control: return controls = None - if settings["relating_control"].Controls: - controls = settings["relating_control"].Controls[0] + if relating_control.Controls: + controls = relating_control.Controls[0] if controls: - if settings["related_object"] in controls.RelatedObjects: + if related_object in controls.RelatedObjects: return related_objects = set(controls.RelatedObjects) - related_objects.add(settings["related_object"]) + related_objects.add(related_object) controls.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(file, **{"element": controls}) else: @@ -99,8 +91,8 @@ def assign_control( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": [settings["related_object"]], - "RelatingControl": settings["relating_control"], + "RelatedObjects": [related_object], + "RelatingControl": relating_control, }, ) return controls diff --git a/src/ifcopenshell-python/ifcopenshell/api/control/unassign_control.py b/src/ifcopenshell-python/ifcopenshell/api/control/unassign_control.py index 77530316d8..44cc4fad6e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/control/unassign_control.py +++ b/src/ifcopenshell-python/ifcopenshell/api/control/unassign_control.py @@ -31,12 +31,9 @@ def unassign_control( :param relating_control: The IfcControl entity that is creating the control or constraint - :type relating_control: ifcopenshell.entity_instance :param related_object: The IfcObjectDefinition that is being controlled - :type related_object: ifcopenshell.entity_instance :return: If the control still is related to other objects, the IfcRelAssignsToControl is returned, otherwise None. - :rtype: ifcopenshell.entity_instance, None Example: @@ -54,14 +51,8 @@ def unassign_control( ifcopenshell.api.control.unassign_control(model, relating_control=cost_item, related_object=wall) """ - - settings = { - "relating_control": relating_control, - "related_object": related_object, - } - - for rel in settings["related_object"].HasAssignments or []: - if not rel.is_a("IfcRelAssignsToControl") or rel.RelatingControl != settings["relating_control"]: + for rel in related_object.HasAssignments or []: + if not rel.is_a("IfcRelAssignsToControl") or rel.RelatingControl != relating_control: continue if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory @@ -70,7 +61,7 @@ def unassign_control( ifcopenshell.util.element.remove_deep2(file, history) return related_objects = list(rel.RelatedObjects) - related_objects.remove(settings["related_object"]) + related_objects.remove(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py index c2a020cac8..58f3ed343a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_item_quantity.py @@ -54,12 +54,9 @@ def add_cost_item_quantity( using another API call. :param cost_item: The IfcCostItem to add the quantity to - :type cost_item: ifcopenshell.entity_instance :param ifc_class: The type of quantity to add - :type ifc_class: str, optional :return: The newly created quantity entity, chosen from the ifc_class parameter - :rtype: ifcopenshell.entity_instance Example: @@ -76,20 +73,18 @@ def add_cost_item_quantity( ifcopenshell.api.cost.add_cost_item_quantity(model, cost_item=item, ifc_class="IfcQuantityCount") """ - settings = {"cost_item": cost_item, "ifc_class": ifc_class} - - quantity = file.create_entity(settings["ifc_class"], Name="Unnamed") + quantity = file.create_entity(ifc_class, Name="Unnamed") # 3 IfcPhysicalSimpleQuantity Value # This is a bold assumption # https://forums.buildingsmart.org/t/how-does-a-cost-item-know-that-it-is-counting-a-controlled-product/3564 - if settings["ifc_class"] == "IfcQuantityCount": + if ifc_class == "IfcQuantityCount": count = 0 - for rel in settings["cost_item"].Controls: + for rel in cost_item.Controls: count += len(rel.RelatedObjects) quantity[3] = count else: quantity[3] = 0.0 - quantities = list(settings["cost_item"].CostQuantities or []) + quantities = list(cost_item.CostQuantities or []) quantities.append(quantity) - settings["cost_item"].CostQuantities = quantities + cost_item.CostQuantities = quantities return quantity diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py index 2231c8c07f..d85534bb83 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_schedule.py @@ -39,13 +39,10 @@ def add_cost_schedule( managing any cost items. :param name: The name of the cost schedule. - :type name: str, optional :param predefined_type: The predefined type of the cost schedule, chosen from a valid type in the IFC documentation for IfcCostScheduleTypeEnum - :type predefined_type: str, optional :return: The newly created IfcCostSchedule entity - :rtype: ifcopenshell.entity_instance Example: @@ -55,13 +52,11 @@ def add_cost_schedule( # Now that we have a cost schedule, we may add cost items to it item = ifcopenshell.api.cost.add_cost_item(model, cost_schedule=schedule) """ - settings = {"name": name, "predefined_type": predefined_type} - cost_schedule = ifcopenshell.api.root.create_entity( file, ifc_class="IfcCostSchedule", - predefined_type=settings["predefined_type"], - name=settings["name"], + predefined_type=predefined_type, + name=name, ) if file.schema == "IFC2X3": cost_schedule.UpdateDate = createIfcDateAndTime(file, datetime.now()) diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py index ebee87ee44..972849ca96 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/add_cost_value.py @@ -46,9 +46,7 @@ def add_cost_value(file: ifcopenshell.file, parent: ifcopenshell.entity_instance :param parent: A parent IfcCostItem, if specifying a price directly to a cost item, or a top-level price component. Alternatively, this can be set to a IfcCostValue, if specifying price subcomponents. - :type parent: ifcopenshell.entity_instance :return: The newly created IfcCostValue - :rtype: ifcopenshell.entity_instance Example: @@ -91,19 +89,17 @@ def add_cost_value(file: ifcopenshell.file, parent: ifcopenshell.entity_instance ifcopenshell.api.cost.edit_cost_value(model, cost_value=subvalue2, attributes={"AppliedValue": 3.0}) """ - settings = {"parent": parent} - value = file.create_entity("IfcCostValue") - if settings["parent"].is_a("IfcCostItem"): - values = list(settings["parent"].CostValues or []) + if parent.is_a("IfcCostItem"): + values = list(parent.CostValues or []) values.append(value) - settings["parent"].CostValues = values - elif settings["parent"].is_a("IfcConstructionResource"): - values = list(settings["parent"].BaseCosts or []) + parent.CostValues = values + elif parent.is_a("IfcConstructionResource"): + values = list(parent.BaseCosts or []) values.append(value) - settings["parent"].BaseCosts = values - elif settings["parent"].is_a("IfcCostValue"): - values = list(settings["parent"].Components or []) + parent.BaseCosts = values + elif parent.is_a("IfcCostValue"): + values = list(parent.Components or []) values.append(value) - settings["parent"].Components = values + parent.Components = values return value diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py index 2eeb02f89d..d012c02c5b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/assign_cost_value.py @@ -36,11 +36,8 @@ def assign_cost_value( rates as a "template" to quickly populate your rates from. :param cost_item: The IfcCostItem that you want to copy the values to - :type cost_item: ifcopenshell.entity_instance :param cost_rate: The IfcCostItem that you want to copy the values from - :type cost_rate: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -61,16 +58,14 @@ def assign_cost_value( # Now the cost item has the same rate as the one from the schedule of rate's item ifcopenshell.api.cost.assign_cost_value(model, cost_item=item, cost_rate=rate) """ - settings = {"cost_item": cost_item, "cost_rate": cost_rate} - - if settings["cost_item"].CostValues: + if cost_item.CostValues: [ ifcopenshell.api.cost.remove_cost_value( file, - parent=settings["cost_item"], + parent=cost_item, cost_value=cost_value, ) - for cost_value in settings["cost_item"].CostValues + for cost_value in cost_item.CostValues ] # This is an assumption, and not part of the official IFC documentation - settings["cost_item"].CostValues = settings["cost_rate"].CostValues + cost_item.CostValues = cost_rate.CostValues diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py b/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py index e1eb12db85..86e149ebd3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/calculate_cost_item_resource_value.py @@ -83,13 +83,11 @@ def calculate_cost_item_resource_value(file: ifcopenshell.file, cost_item: ifcop # (42 * 200) + 50000 = 58400 is our calculated cost ifcopenshell.api.cost.calculate_cost_item_resource_value(model, cost_item=item) """ - settings = {"cost_item": cost_item} - - for cost_value in settings["cost_item"].CostValues or []: - ifcopenshell.api.cost.remove_cost_value(file, parent=settings["cost_item"], cost_value=cost_value) + for cost_value in cost_item.CostValues or []: + ifcopenshell.api.cost.remove_cost_value(file, parent=cost_item, cost_value=cost_value) resources = [] - for rel in settings["cost_item"].Controls or []: + for rel in cost_item.Controls or []: for related_object in rel.RelatedObjects: if related_object.is_a("IfcConstructionResource"): resources.append(related_object) @@ -112,6 +110,6 @@ def calculate_cost_item_resource_value(file: ifcopenshell.file, cost_item: ifcop if unit and "day" in unit: quantity = quantity / 8 # Assume 8 hour working day - TODO implement resource calendar formula = "{}*{}".format(cost, quantity) - cost_value = ifcopenshell.api.cost.add_cost_value(file, parent=settings["cost_item"]) + cost_value = ifcopenshell.api.cost.add_cost_value(file, parent=cost_item) cost_value.Name = resource.Name ifcopenshell.api.cost.edit_cost_value_formula(file, cost_value=cost_value, formula=formula) diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py index bb9b1bd18d..b5acaaf1cc 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_item.py @@ -29,9 +29,7 @@ def remove_cost_item(file: ifcopenshell.file, cost_item: ifcopenshell.entity_ins retained. :param cost_item: The IfcCostItem entity you want to remove - :type cost_item: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -41,15 +39,13 @@ def remove_cost_item(file: ifcopenshell.file, cost_item: ifcopenshell.entity_ins item = ifcopenshell.api.cost.add_cost_item(model, cost_schedule=schedule) ifcopenshell.api.cost.remove_cost_item(model, cost_item=item) """ - settings = {"cost_item": cost_item} - # TODO: do a deep purge - for inverse in file.get_inverse(settings["cost_item"]): + for inverse in file.get_inverse(cost_item): if inverse.is_a("IfcRelNests"): - if inverse.RelatingObject == settings["cost_item"]: + if inverse.RelatingObject == cost_item: for related_object in inverse.RelatedObjects: ifcopenshell.api.cost.remove_cost_item(file, cost_item=related_object) - elif inverse.RelatedObjects == (settings["cost_item"],): + elif inverse.RelatedObjects == (cost_item,): history = inverse.OwnerHistory file.remove(inverse) if history: @@ -59,7 +55,7 @@ def remove_cost_item(file: ifcopenshell.file, cost_item: ifcopenshell.entity_ins file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) - history = settings["cost_item"].OwnerHistory - file.remove(settings["cost_item"]) + history = cost_item.OwnerHistory + file.remove(cost_item) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py index f5591ee9b1..0e05708f7f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/cost/remove_cost_schedule.py @@ -40,17 +40,15 @@ def remove_cost_schedule(file: ifcopenshell.file, cost_schedule: ifcopenshell.en item = ifcopenshell.api.cost.add_cost_item(model, cost_schedule=schedule) ifcopenshell.api.cost.remove_cost_schedule(model, cost_schedule=schedule) """ - settings = {"cost_schedule": cost_schedule} - # TODO: do a deep purge - for inverse in file.get_inverse(settings["cost_schedule"]): + for inverse in file.get_inverse(cost_schedule): if inverse.is_a("IfcRelAssignsToControl"): [ ifcopenshell.api.cost.remove_cost_item(file, cost_item=related_object) for related_object in inverse.RelatedObjects if related_object.is_a("IfcCostItem") ] - history = settings["cost_schedule"].OwnerHistory - file.remove(settings["cost_schedule"]) + history = cost_schedule.OwnerHistory + file.remove(cost_schedule) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/document/add_reference.py b/src/ifcopenshell-python/ifcopenshell/api/document/add_reference.py index 0fd2361c8d..ae56b0b935 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/document/add_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/document/add_reference.py @@ -38,9 +38,7 @@ def add_reference(file: ifcopenshell.file, information: ifcopenshell.entity_inst :param information: The IfcDocumentInformation that the reference will be created for - :type information: ifcopenshell.entity_instance :return: The newly created IfcDocumentReference entity - :rtype: ifcopenshell.entity_instance Example: @@ -63,13 +61,11 @@ def add_reference(file: ifcopenshell.file, information: ifcopenshell.entity_inst ifcopenshell.api.document.edit_reference(model, reference=reference2, attributes={"Identification": "2.1.15"}) """ - settings = {"information": information} - if file.schema == "IFC2X3": reference = file.create_entity("IfcDocumentReference", ItemReference="X") - if settings["information"]: - references = list(settings["information"].DocumentReferences or []) + if information: + references = list(information.DocumentReferences or []) references.append(reference) - settings["information"].DocumentReferences = references + information.DocumentReferences = references return reference - return file.create_entity("IfcDocumentReference", ReferencedDocument=settings["information"], Identification="X") + return file.create_entity("IfcDocumentReference", ReferencedDocument=information, Identification="X") diff --git a/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py b/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py index 6de39062f9..a81ae71973 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py +++ b/src/ifcopenshell-python/ifcopenshell/api/document/unassign_document.py @@ -30,12 +30,9 @@ def unassign_document( :param product: The list of objects that the document reference or information is related to. - :type product: list[ifcopenshell.entity_instance] :param document: The IfcDocumentReference (typically) or in rare cases the IfcDocumentInformation that is associated with the product - :type document: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -54,27 +51,21 @@ def unassign_document( # Now let's change our mind and remove the association ifcopenshell.api.document.unassign_document(model, products=[storey], document=reference) """ - settings = { - "products": products, - "document": document, - } # TODO: do we need to support non-ifcroot elements like we do in classification.add_reference? # NOTE: reuses code from `library.un assign_reference` reference_rels: set[ifcopenshell.entity_instance] = set() - products = set(settings["products"]) - for product in products: + products_set = set(products) + for product in products_set: reference_rels.update(product.HasAssociations) reference_rels = { - rel - for rel in reference_rels - if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == settings["document"] + rel for rel in reference_rels if rel.is_a("IfcRelAssociatesDocument") and rel.RelatingDocument == document } for rel in reference_rels: - related_objects = set(rel.RelatedObjects) - products + related_objects = set(rel.RelatedObjects) - products_set if related_objects: rel.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) diff --git a/src/ifcopenshell-python/ifcopenshell/api/drawing/assign_product.py b/src/ifcopenshell-python/ifcopenshell/api/drawing/assign_product.py index fcd739ffad..87f786d807 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/drawing/assign_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/drawing/assign_product.py @@ -46,12 +46,9 @@ def assign_product( in 3D. :param relating_product: The IfcProduct the object is related to - :type relating_product: ifcopenshell.entity_instance :param related_object: The object (typically IfcAnnotation) that the product is related to - :type related_object: ifcopenshell.entity_instance :return: The created IfcRelAssignsToProduct relationship - :rtype: ifcopenshell.entity_instance Example: @@ -62,42 +59,36 @@ def assign_product( ifcopenshell.api.drawing.assign_product(model, relating_product=furniture, related_object=annotation) """ - settings = { - "relating_product": relating_product, - "related_object": related_object, - } - - is_grid_axis = settings["relating_product"].is_a("IfcGridAxis") + is_grid_axis = relating_product.is_a("IfcGridAxis") if is_grid_axis: - if settings["related_object"].HasAssignments: - for rel in settings["related_object"].HasAssignments: - if rel.is_a("IfcRelAssignsToProduct") and rel.Name == settings["relating_product"].AxisTag: + if related_object.HasAssignments: + for rel in related_object.HasAssignments: + if rel.is_a("IfcRelAssignsToProduct") and rel.Name == relating_product.AxisTag: return - elif settings["related_object"].HasAssignments: - for rel in settings["related_object"].HasAssignments: - if rel.is_a("IfcRelAssignsToProduct") and rel.RelatingProduct == settings["relating_product"]: + elif related_object.HasAssignments: + for rel in related_object.HasAssignments: + if rel.is_a("IfcRelAssignsToProduct") and rel.RelatingProduct == relating_product: return referenced_by = None if is_grid_axis: - axis = settings["relating_product"] + axis = relating_product grid = None for attribute in ("PartOfW", "PartOfV", "PartOfU"): if getattr(axis, attribute, None): grid = getattr(axis, attribute)[0] - settings["relating_product"] = grid for rel in grid.ReferencedBy: if rel.Name == axis.AxisTag: referenced_by = rel break - elif settings["relating_product"].ReferencedBy: - referenced_by = settings["relating_product"].ReferencedBy[0] + elif relating_product.ReferencedBy: + referenced_by = relating_product.ReferencedBy[0] if referenced_by: related_objects = list(referenced_by.RelatedObjects) - related_objects.append(settings["related_object"]) + related_objects.append(related_object) referenced_by.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": referenced_by}) else: @@ -106,8 +97,8 @@ def assign_product( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": [settings["related_object"]], - "RelatingProduct": settings["relating_product"], + "RelatedObjects": [related_object], + "RelatingProduct": relating_product, }, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/drawing/unassign_product.py b/src/ifcopenshell-python/ifcopenshell/api/drawing/unassign_product.py index 03812040cc..f95a98a1fe 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/drawing/unassign_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/drawing/unassign_product.py @@ -34,12 +34,9 @@ def unassign_product( object later or leave the annotation as a "dumb" annotation. :param relating_product: The IfcProduct the object is related to - :type relating_product: ifcopenshell.entity_instance :param related_object: The object (typically IfcAnnotation) that the product is related to - :type related_object: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -54,13 +51,8 @@ def unassign_product( ifcopenshell.api.drawing.unassign_product(model, relating_product=furniture, related_object=annotation) """ - settings = { - "relating_product": relating_product, - "related_object": related_object, - } - - for rel in settings["related_object"].HasAssignments or []: - if not rel.is_a("IfcRelAssignsToProduct") or rel.RelatingProduct != settings["relating_product"]: + for rel in related_object.HasAssignments or []: + if not rel.is_a("IfcRelAssignsToProduct") or rel.RelatingProduct != relating_product: continue if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory @@ -69,6 +61,6 @@ def unassign_product( ifcopenshell.util.element.remove_deep2(file, history) return related_objects = list(rel.RelatedObjects) - related_objects.remove(settings["related_object"]) + related_objects.remove(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, element=rel) diff --git a/src/ifcopenshell-python/ifcopenshell/api/feature/add_filling.py b/src/ifcopenshell-python/ifcopenshell/api/feature/add_filling.py index 7f59d65ec8..bb6035cd79 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/feature/add_filling.py +++ b/src/ifcopenshell-python/ifcopenshell/api/feature/add_filling.py @@ -33,11 +33,8 @@ def add_filling( filled. :param opening: The IfcOpeningElement to fill with the element. - :type opening: ifcopenshell.entity_instance :param element: The IfcElement to be inserted into the opening. - :type element: ifcopenshell.entity_instance :return: The new IfcRelFillsElement relationship - :rtype: ifcopenshell.entity_instance Example: @@ -102,12 +99,10 @@ def add_filling( # The door will now fill the opening. ifcopenshell.api.feature.add_filling(model, opening=opening, element=door) """ - settings = {"opening": opening, "element": element} - - fills_voids = settings["element"].FillsVoids + fills_voids = element.FillsVoids if fills_voids: - if fills_voids[0].RelatingOpeningElement == settings["opening"]: + if fills_voids[0].RelatingOpeningElement == opening: return fills_voids[0] history = fills_voids[0].OwnerHistory file.remove(fills_voids[0]) @@ -117,6 +112,6 @@ def add_filling( return file.create_entity( "IfcRelFillsElement", GlobalId=ifcopenshell.guid.new(), - RelatingOpeningElement=settings["opening"], - RelatedBuildingElement=settings["element"], + RelatingOpeningElement=opening, + RelatedBuildingElement=element, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/feature/remove_filling.py b/src/ifcopenshell-python/ifcopenshell/api/feature/remove_filling.py index f6931b4f9d..b009b1e0c4 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/feature/remove_filling.py +++ b/src/ifcopenshell-python/ifcopenshell/api/feature/remove_filling.py @@ -28,9 +28,7 @@ def remove_filling(file: ifcopenshell.file, element: ifcopenshell.entity_instanc fills the opening. :param element: The element filling an opening. - :type element: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -52,10 +50,8 @@ def remove_filling(file: ifcopenshell.file, element: ifcopenshell.entity_instanc # Not anymore! ifcopenshell.api.feature.remove_filling(model, element=door) """ - settings = {"element": element} - for rel in file.by_type("IfcRelFillsElement"): - if rel.RelatedBuildingElement == settings["element"]: + if rel.RelatedBuildingElement == element: history = rel.OwnerHistory file.remove(rel) if history: diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_axis_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_axis_representation.py index 174c475f92..02bd057cc6 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_axis_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_axis_representation.py @@ -56,13 +56,10 @@ def add_axis_representation( :param context: The IfcGeometricRepresentationContext that the representation is part of. This must be either a Model/Axis/GRAPH_VIEW (3D) or Plan/Axis/GRAPH_VIEW (2D). - :type context: ifcopenshell.entity_instance :param axis: The axis, as a list of two coordinates, the coordinates being either a list of 2 or 3 float coordinates depending on whether the axis is 2D or 3D. - :type axis: list[list[float]] :return: The newly created IfcShapeRepresentation entity - :rtype: ifcopenshell.entity_instance Example: diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/connect_element.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/connect_element.py index 89c0c1be19..f737b54c77 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/connect_element.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/connect_element.py @@ -29,20 +29,14 @@ def connect_element( related_element: ifcopenshell.entity_instance, description: Optional[str] = None, ) -> ifcopenshell.entity_instance: - settings = { - "relating_element": relating_element, - "related_element": related_element, - "description": description, - } - incompatible_connections = [] - for rel in settings["relating_element"].ConnectedFrom: - if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == settings["related_element"]: + for rel in relating_element.ConnectedFrom: + if rel.is_a() == "IfcRelConnectsElements" and rel.RelatingElement == related_element: incompatible_connections.append(rel) - for rel in settings["related_element"].ConnectedTo: - if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == settings["relating_element"]: + for rel in related_element.ConnectedTo: + if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == relating_element: incompatible_connections.append(rel) if incompatible_connections: @@ -52,15 +46,15 @@ def connect_element( if history: ifcopenshell.util.element.remove_deep2(file, history) - for rel in settings["relating_element"].ConnectedTo: - if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == settings["related_element"]: - rel.Description = settings["description"] + for rel in relating_element.ConnectedTo: + if rel.is_a() == "IfcRelConnectsElements" and rel.RelatedElement == related_element: + rel.Description = description return rel return file.createIfcRelConnectsElements( ifcopenshell.guid.new(), OwnerHistory=ifcopenshell.api.owner.create_owner_history(file), - Description=settings["description"], - RelatingElement=settings["relating_element"], - RelatedElement=settings["related_element"], + Description=description, + RelatingElement=relating_element, + RelatedElement=related_element, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/map_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/map_representation.py index b559a66d5f..e868beea66 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/map_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/map_representation.py @@ -17,7 +17,6 @@ # along with IfcOpenShell. If not, see . import ifcopenshell -from typing import Any def map_representation( @@ -25,15 +24,14 @@ def map_representation( ) -> ifcopenshell.entity_instance: usecase = Usecase() usecase.file = file - usecase.settings = {"representation": representation} - return usecase.execute() + return usecase.execute(representation) class Usecase: file: ifcopenshell.file - settings: dict[str, Any] - def execute(self) -> ifcopenshell.entity_instance: + def execute(self, representation: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance: + self.representation = representation mapping_source = self.get_mapping_source() zero = self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)) @@ -46,15 +44,15 @@ class Usecase: return self.file.create_entity( "IfcShapeRepresentation", **{ - "ContextOfItems": self.settings["representation"].ContextOfItems, - "RepresentationIdentifier": self.settings["representation"].RepresentationIdentifier, + "ContextOfItems": representation.ContextOfItems, + "RepresentationIdentifier": representation.RepresentationIdentifier, "RepresentationType": "MappedRepresentation", "Items": [mapped_item], } ) def get_mapping_source(self) -> ifcopenshell.entity_instance: - for inverse in self.file.get_inverse(self.settings["representation"]): + for inverse in self.file.get_inverse(self.representation): if inverse.is_a("IfcRepresentationMap"): return inverse zero = self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)) @@ -62,5 +60,5 @@ class Usecase: z_axis = self.file.createIfcDirection((0.0, 0.0, 1.0)) mapping_origin = self.file.createIfcAxis2Placement3D(zero, z_axis, x_axis) return self.file.createIfcRepresentationMap( - MappingOrigin=mapping_origin, MappedRepresentation=self.settings["representation"] + MappingOrigin=mapping_origin, MappedRepresentation=self.representation ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py b/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py index eb40127209..a2a877ef6e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py +++ b/src/ifcopenshell-python/ifcopenshell/api/group/add_group.py @@ -35,12 +35,9 @@ def add_group( or structural load groups, which group together loads for structural analysis, or inventories, which are groups of assets. - :param Name: The name of the group. Defaults to "Unnamed" - :type Name: str, optional + :param name: The name of the group. Defaults to "Unnamed" :param description: The description of the purpose of the group. - :type description: str, optional :return: The newly created IfcGroup - :rtype: ifcopenshell.entity_instance Example: @@ -48,17 +45,11 @@ def add_group( ifcopenshell.api.group.add_group(model, name="Unit 1A") """ - settings = { - "name": name or "Unnamed", - "description": description, - } return file.create_entity( "IfcGroup", - **{ - "GlobalId": ifcopenshell.guid.new(), - "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "Name": settings["name"], - "Description": settings["description"], - } + GlobalId=ifcopenshell.guid.new(), + OwnerHistory=ifcopenshell.api.owner.create_owner_history(file), + Name=name, + Description=description, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/group/remove_group.py b/src/ifcopenshell-python/ifcopenshell/api/group/remove_group.py index 3f3987f66a..34011eeca9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/group/remove_group.py +++ b/src/ifcopenshell-python/ifcopenshell/api/group/remove_group.py @@ -39,9 +39,7 @@ def remove_group(file: ifcopenshell.file, group: ifcopenshell.entity_instance) - group = ifcopenshell.api.group.add_group(model, name="Unit 1A") ifcopenshell.api.group.remove_group(model, group=group) """ - settings = {"group": group} - - for inverse_id in [i.id() for i in file.get_inverse(settings["group"])]: + for inverse_id in [i.id() for i in file.get_inverse(group)]: try: inverse = file.by_id(inverse_id) except: @@ -49,11 +47,11 @@ def remove_group(file: ifcopenshell.file, group: ifcopenshell.entity_instance) - if inverse.is_a("IfcRelDefinesByProperties"): ifcopenshell.api.pset.remove_pset( file, - product=settings["group"], + product=group, pset=inverse.RelatingPropertyDefinition, ) elif inverse.is_a("IfcRelAssignsToGroup"): - if inverse.RelatingGroup == settings["group"]: + if inverse.RelatingGroup == group: history = inverse.OwnerHistory file.remove(inverse) if history: @@ -63,7 +61,7 @@ def remove_group(file: ifcopenshell.file, group: ifcopenshell.entity_instance) - file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) - history = settings["group"].OwnerHistory - file.remove(settings["group"]) + history = group.OwnerHistory + file.remove(group) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/library/add_reference.py b/src/ifcopenshell-python/ifcopenshell/api/library/add_reference.py index 428e0b01d7..8e138954d5 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/library/add_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/library/add_reference.py @@ -50,14 +50,10 @@ def add_reference(file: ifcopenshell.file, library: ifcopenshell.entity_instance ifcopenshell.api.library.edit_reference(model, reference=reference, attributes={"Identification": "http://example.org/digitaltwin#AHU01"}) """ - settings = { - "library": library, - } - if file.schema == "IFC2X3": reference = file.createIfcLibraryReference() - references = list(settings["library"].LibraryReference or []) + references = list(library.LibraryReference or []) references.append(reference) - settings["library"].LibraryReference = references + library.LibraryReference = references return reference - return file.createIfcLibraryReference(ReferencedLibrary=settings["library"]) + return file.createIfcLibraryReference(ReferencedLibrary=library) diff --git a/src/ifcopenshell-python/ifcopenshell/api/library/assign_reference.py b/src/ifcopenshell-python/ifcopenshell/api/library/assign_reference.py index 40b3a92f56..a9b6169304 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/library/assign_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/library/assign_reference.py @@ -33,14 +33,11 @@ def assign_reference( detail about how references work. :param products: The list of IfcProducts you want to associate with the reference - :type products: list[ifcopenshell.entity_instance] :param reference: The IfcLibraryReference you want the product to be associated with. - :type reference: ifcopenshell.entity_instance :return: The IfcRelAssociatesLibrary relationship entity or `None` if `products` was an empty list or all products were already assigned to the `reference`. - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -60,38 +57,33 @@ def assign_reference( # And now assign the IFC model's AHU with its Brickschema counterpart ifcopenshell.api.library.assign_reference(model, reference=reference, products=[ahu]) """ - settings = { - "products": products, - "reference": reference, - } - # TODO: do we need to support non-ifcroot elements like we do in classification.add_reference? - referenced_elements = ifcopenshell.util.element.get_referenced_elements(settings["reference"]) - products: set[ifcopenshell.entity_instance] = set(settings["products"]) - products = products - referenced_elements + referenced_elements = ifcopenshell.util.element.get_referenced_elements(reference) + products_set: set[ifcopenshell.entity_instance] = set(products) + products_set = products_set - referenced_elements - if not products: + if not products_set: return if file.schema == "IFC2X3": rel = next( - (r for r in file.by_type("IfcRelAssociatesLibrary") if r.RelatingLibrary == settings["reference"]), + (r for r in file.by_type("IfcRelAssociatesLibrary") if r.RelatingLibrary == reference), None, ) else: - rel = next(iter(settings["reference"].LibraryRefForObjects), None) + rel = next(iter(reference.LibraryRefForObjects), None) if not rel: return file.create_entity( "IfcRelAssociatesLibrary", GlobalId=ifcopenshell.guid.new(), OwnerHistory=ifcopenshell.api.owner.create_owner_history(file), - RelatedObjects=list(products), - RelatingLibrary=settings["reference"], + RelatedObjects=list(products_set), + RelatingLibrary=reference, ) - related_objects = set(rel.RelatedObjects) | products + related_objects = set(rel.RelatedObjects) | products_set rel.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(file, element=rel) return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/library/unassign_reference.py b/src/ifcopenshell-python/ifcopenshell/api/library/unassign_reference.py index 876a9b86e6..d92ed2fc1e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/library/unassign_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/library/unassign_reference.py @@ -31,11 +31,8 @@ def unassign_reference( If the product isn't assigned to the reference, nothing will happen. :param reference: The IfcLibraryReference to unassign from - :type reference: ifcopenshell.entity_instance :param products: A list of IfcProduct elements to unassign from the reference - :type products: list[ifcopenshell.entity_instance] :return: None - :rtype: None Example: @@ -58,24 +55,19 @@ def unassign_reference( # Let's change our mind and unassign it. ifcopenshell.api.library.unassign_reference(model, reference=reference, products=[ahu]) """ - - settings = {"reference": reference, "products": products} - # TODO: do we need to support non-ifcroot elements like we do in classification.add_reference? reference_rels: set[ifcopenshell.entity_instance] = set() - products = set(settings["products"]) - for product in products: + products_set = set(products) + for product in products_set: reference_rels.update(product.HasAssociations) reference_rels = { - rel - for rel in reference_rels - if rel.is_a("IfcRelAssociatesLibrary") and rel.RelatingLibrary == settings["reference"] + rel for rel in reference_rels if rel.is_a("IfcRelAssociatesLibrary") and rel.RelatingLibrary == reference } for rel in reference_rels: - related_objects = set(rel.RelatedObjects) - products + related_objects = set(rel.RelatedObjects) - products_set if related_objects: rel.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py index 944a835493..994d4665ef 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_list_item.py @@ -40,11 +40,8 @@ def add_list_item( :param material_list: The IfcMaterialList the material should be added to. - :type material_list: ifcopenshell.entity_instance :param material: The IfcMaterial to add to the list - :type material: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -80,8 +77,6 @@ def add_list_item( # aluminium and glass. ifcopenshell.api.material.assign_material(model, products=[window_type], material=material_set) """ - settings = {"material_list": material_list, "material": material} - - materials = list(settings["material_list"].Materials or []) - materials.append(settings["material"]) - settings["material_list"].Materials = materials + materials = list(material_list.Materials or []) + materials.append(material) + material_list.Materials = materials diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py index d938c75380..6b04f78be2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_material.py @@ -58,13 +58,9 @@ def add_material( :param name: The name of the material, typically tagged in a finishes drawing or schedule. - :type name: str, optional :param category: The category of the material. - :type category: str, optional :param description: A description of the material. - :type description: str, optional :return: The newly created IfcMaterial - :rtype: ifcopenshell.entity_instance Example: @@ -81,11 +77,9 @@ def add_material( # "Style" has been specified. ifcopenshell.api.material.assign_material(model, products=[concrete_bench], material=concrete) """ - settings = {"name": name or "Unnamed", "category": category, "description": description} - - material = file.create_entity("IfcMaterial", **{"Name": settings["name"] or "Unnamed"}) - if settings["category"]: - material.Category = settings["category"] - if settings["description"]: - material.Description = settings["description"] + material = file.create_entity("IfcMaterial", **{"Name": name or "Unnamed"}) + if category: + material.Category = category + if description: + material.Description = description return material diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py b/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py index 72c090b1ae..bd23688ac8 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/add_material_set.py @@ -68,14 +68,11 @@ def add_material_set( :param name: The name of the material set, which may be purely descriptive or annotated in drawings. Defaults to "Unnamed". - :type name: str, optional :param set_type: What type of set you want to create, chosen from IfcMaterialLayerSet, IfcMaterialProfileSet, IfcMaterialConstituentSet, or IfcMaterialList. Defaults to IfcMaterialConstituentSet. - :type set_type: str, optional :return: The newly created material set element - :rtype: ifcopenshell.entity_instance Example: @@ -113,10 +110,8 @@ def add_material_set( # Great! Let's assign our material set to our wall type. ifcopenshell.api.material.assign_material(model, products=[wall_type], material=material_set) """ - settings = {"name": name or "Unnamed", "set_type": set_type} - - if settings["set_type"] == "IfcMaterialLayerSet": - return file.create_entity("IfcMaterialLayerSet", LayerSetName=settings["name"] or "Unnamed") - elif settings["set_type"] == "IfcMaterialList": + if set_type == "IfcMaterialLayerSet": + return file.create_entity("IfcMaterialLayerSet", LayerSetName=name or "Unnamed") + elif set_type == "IfcMaterialList": return file.create_entity("IfcMaterialList") - return file.create_entity(settings["set_type"], Name=settings["name"] or "Unnamed") + return file.create_entity(set_type, Name=name or "Unnamed") diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/remove_material.py b/src/ifcopenshell-python/ifcopenshell/api/material/remove_material.py index d9894b0d96..c919f1f629 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/remove_material.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/remove_material.py @@ -29,9 +29,7 @@ def remove_material(file: ifcopenshell.file, material: ifcopenshell.entity_insta take care of this situation themselves. :param material: The IfcMaterial entity you want to remove - :type material: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -43,10 +41,8 @@ def remove_material(file: ifcopenshell.file, material: ifcopenshell.entity_insta # ... and remove it ifcopenshell.api.material.remove_material(model, material=aluminium) """ - settings = {"material": material} - - inverse_elements = file.get_inverse(settings["material"]) - file.remove(settings["material"]) + inverse_elements = file.get_inverse(material) + file.remove(material) # TODO: Right now, we we choose only to delete set items (e.g. a layer) but not the material set # This can lead to invalid material sets, but we assume the user will deal with it for inverse in inverse_elements: diff --git a/src/ifcopenshell-python/ifcopenshell/api/material/remove_material_set.py b/src/ifcopenshell-python/ifcopenshell/api/material/remove_material_set.py index 30edd7ad9e..51decaaa98 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/material/remove_material_set.py +++ b/src/ifcopenshell-python/ifcopenshell/api/material/remove_material_set.py @@ -29,9 +29,7 @@ def remove_material_set(file: ifcopenshell.file, material: ifcopenshell.entity_i :param material: The IfcMaterialLayerSet, IfcMaterialConstituentSet, IfcMaterialProfileSet entity you want to remove. - :type material: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -55,20 +53,18 @@ def remove_material_set(file: ifcopenshell.file, material: ifcopenshell.entity_i ifcopenshell.api.material.remove_material_set(model, material=material_set) """ - settings = {"material": material} - - inverse_elements = file.get_inverse(settings["material"]) - if settings["material"].is_a("IfcMaterialLayerSet"): - set_items = settings["material"].MaterialLayers or [] - elif settings["material"].is_a("IfcMaterialProfileSet"): - set_items = settings["material"].MaterialProfiles or [] - elif settings["material"].is_a("IfcMaterialConstituentSet"): - set_items = settings["material"].MaterialConstituents or [] - elif settings["material"].is_a("IfcMaterialList"): + inverse_elements = file.get_inverse(material) + if material.is_a("IfcMaterialLayerSet"): + set_items = material.MaterialLayers or [] + elif material.is_a("IfcMaterialProfileSet"): + set_items = material.MaterialProfiles or [] + elif material.is_a("IfcMaterialConstituentSet"): + set_items = material.MaterialConstituents or [] + elif material.is_a("IfcMaterialList"): set_items = [] for set_item in set_items: file.remove(set_item) - file.remove(settings["material"]) + file.remove(material) for inverse in inverse_elements: if inverse.is_a("IfcRelAssociatesMaterial"): history = inverse.OwnerHistory diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py index 284020a224..1456a99d5e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_actor.py @@ -49,11 +49,8 @@ def add_actor( IfcPerson if it is a sole individual, or an IfcPersonAndOrganization if a specific person is liable within an organisation and must be legally nominated. - :type actor: ifcopenshell.entity_instance :param ifc_class: Either "IfcActor" or "IfcOccupant". - :type ifc_class: str, optional :return: The newly created IfcActor or IfcOccupant - :rtype: ifcopenshell.entity_instance Example: @@ -67,8 +64,7 @@ def add_actor( # Assign that organisation to a newly created actor actor = ifcopenshell.api.owner.add_actor(model, actor=organisation) """ - settings = {"actor": actor, "ifc_class": ifc_class or "IfcActor"} - - actor = ifcopenshell.api.root.create_entity(file, ifc_class=settings["ifc_class"]) - actor.TheActor = settings["actor"] - return actor + ifc_class = ifc_class or "IfcActor" + actor_ = ifcopenshell.api.root.create_entity(file, ifc_class=ifc_class) + actor_.TheActor = actor + return actor_ diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py index 5b03f9f18a..791f41c6a2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_address.py @@ -39,12 +39,9 @@ def add_address( :param assigned_object: The IfcOrganization or IfcPerson the contact address belongs to. - :type assigned_object: ifcopenshell.entity_instance :param ifc_class: Either IfcPostalAddress or IfcTelecomAddress. Defaults to IfcPostalAddress. - :type ifc_class: str, optional :return: The new IfcPostalAddress or IfcTelecomAddress - :rtype: ifcopenshell.entity_instance Example: @@ -67,10 +64,8 @@ def add_address( "ElectronicMailAddresses": ["bobthebuilder@example.com"], "WWWHomePageURL": "https://thinkmoult.com"}) """ - settings = {"assigned_object": assigned_object, "ifc_class": ifc_class} - - address = file.create_entity(settings["ifc_class"], "OFFICE") - addresses = list(settings["assigned_object"].Addresses) if settings["assigned_object"].Addresses else [] + address = file.create_entity(ifc_class, "OFFICE") + addresses = list(assigned_object.Addresses) if assigned_object.Addresses else [] addresses.append(address) - settings["assigned_object"].Addresses = addresses + assigned_object.Addresses = addresses return address diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py index b5c2fae582..be308536e3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_organisation.py @@ -31,11 +31,8 @@ def add_organisation( Sometimes used in drawing naming schemes. Otherise used as a canonicalised way of computers to identify the organisation. Like their stock name. - :type identification: str, optional :param name: The legal name of the organisation - :type name: str, optional :return: The newly created IfcOrganization - :rtype: ifcopenshell.entity_instance Example: @@ -44,11 +41,9 @@ def add_organisation( organisation = ifcopenshell.api.owner.add_organisation(model, identification="AWB", name="Architects Without Ballpens") """ - settings = {"identification": identification, "name": name} - - data = {"Name": settings["name"]} + data = {"Name": name} if file.schema == "IFC2X3": - data["Id"] = settings["identification"] + data["Id"] = identification else: - data["Identification"] = settings["identification"] + data["Identification"] = identification return file.create_entity("IfcOrganization", **data) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py index 30d81ef117..1953d80028 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person.py @@ -31,13 +31,9 @@ def add_person( :param identification: The computer readable unique identification of the person. For example, their username in a CDE or alias. - :type identification: str, optional :param family_name: The family name - :type family_name: str, optional :param given_name: The given name - :type given_name: str, optional :return: The newly created IfcPerson - :rtype: ifcopenshell.entity_instance Example: @@ -46,15 +42,9 @@ def add_person( ifcopenshell.api.owner.add_person(model, identification="bobthebuilder", family_name="Thebuilder", given_name="Bob") """ - settings = { - "identification": identification, - "family_name": family_name, - "given_name": given_name, - } - - data = {"FamilyName": settings["family_name"], "GivenName": settings["given_name"]} + data = {"FamilyName": family_name, "GivenName": given_name} if file.schema == "IFC2X3": - data["Id"] = settings["identification"] + data["Id"] = identification else: - data["Identification"] = settings["identification"] + data["Identification"] = identification return file.create_entity("IfcPerson", **data) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py index 6d6a9bdfb7..3fbec452c0 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/add_person_and_organisation.py @@ -30,11 +30,8 @@ def add_person_and_organisation( :param person: The IfcPerson being the representative of the organisation. - :type person: ifcopenshell.entity_instance :param organisation: The IfcOrganization it - :type organisation: ifcopenshell.entity_instance :return: The newly created IfcPersonAndOrganization - :rtype: ifcopenshell.entity_instance Example: @@ -48,6 +45,4 @@ def add_person_and_organisation( ifcopenshell.api.owner.add_person_and_organisation(model, person=person, organisation=organisation) """ - settings = {"person": person, "organisation": organisation} - - return file.createIfcPersonAndOrganization(settings["person"], settings["organisation"]) + return file.create_entity("IfcPersonAndOrganization", person, organisation) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py index dcda100b34..7f2df90511 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/assign_actor.py @@ -43,11 +43,8 @@ def assign_actor( ifcopenshell.api.resource.assign_resource. :param relating_actor: The IfcActor who is responsible for the object. - :type relating_actor: ifcopenshell.entity_instance :param related_object: The object the actor is responsible for. - :type related_object: ifcopenshell.entity_instance :return: The newly created IfcRelAssignsToActor relationship. - :rtype: ifcopenshell.entity_instance Example: @@ -74,24 +71,19 @@ def assign_actor( ifcopenshell.api.owner.assign_actor(model, relating_actor=manufacturer, related_object=pump_type) """ - settings = { - "relating_actor": relating_actor, - "related_object": related_object, - } - - if settings["related_object"].HasAssignments: - for rel in settings["related_object"].HasAssignments: - if rel.is_a("IfcRelAssignsToActor") and rel.RelatingActor == settings["relating_actor"]: + if related_object.HasAssignments: + for rel in related_object.HasAssignments: + if rel.is_a("IfcRelAssignsToActor") and rel.RelatingActor == relating_actor: return rel rel = None - if settings["relating_actor"].IsActingUpon: - rel = settings["relating_actor"].IsActingUpon[0] + if relating_actor.IsActingUpon: + rel = relating_actor.IsActingUpon[0] if rel: related_objects = list(rel.RelatedObjects) - related_objects.append(settings["related_object"]) + related_objects.append(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) else: @@ -100,8 +92,8 @@ def assign_actor( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": [settings["related_object"]], - "RelatingActor": settings["relating_actor"], + "RelatedObjects": [related_object], + "RelatingActor": relating_actor, } ) return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py index 026808b7d2..dd86a6f937 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_actor.py @@ -24,9 +24,7 @@ def remove_actor(file: ifcopenshell.file, actor: ifcopenshell.entity_instance) - """Removes an actor :param actor: The IfcActor to remove. - :type actor: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -44,9 +42,7 @@ def remove_actor(file: ifcopenshell.file, actor: ifcopenshell.entity_instance) - # Actually we need ballpens on this project ifcopenshell.api.owner.remove_actor(model, actor=actor) """ - settings = {"actor": actor} - - history = settings["actor"].OwnerHistory - file.remove(settings["actor"]) + history = actor.OwnerHistory + file.remove(actor) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py index 0d8ff96ff9..28942943a4 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_address.py @@ -25,9 +25,7 @@ def remove_address(file: ifcopenshell.file, address: ifcopenshell.entity_instanc relationship removed. :param address: The IfcAddress to remove. - :type address: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -40,10 +38,8 @@ def remove_address(file: ifcopenshell.file, address: ifcopenshell.entity_instanc # Change our mind and delete it ifcopenshell.api.owner.remove_address(model, address=address) """ - settings = {"address": address} - - for inverse in file.get_inverse(settings["address"]): + for inverse in file.get_inverse(address): if inverse.is_a() in ("IfcOrganization", "IfcPerson"): - if inverse.Addresses == (settings["address"],): + if inverse.Addresses == (address,): inverse.Addresses = None - file.remove(settings["address"]) + file.remove(address) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py index c744d2f97f..1a63bc4949 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_application.py @@ -25,9 +25,7 @@ def remove_application(file: ifcopenshell.file, application: ifcopenshell.entity Check whether or not the application is used anywhere prior to removal. :param address: The IfcApplication to remove. - :type address: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -36,6 +34,4 @@ def remove_application(file: ifcopenshell.file, application: ifcopenshell.entity application = ifcopenshell.api.owner.add_application(model) ifcopenshell.api.owner.remove_address(model, application=application) """ - settings = {"application": application} - - file.remove(settings["application"]) + file.remove(application) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py index 95f137f046..13607b22f3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_person_and_organisation.py @@ -28,9 +28,7 @@ def remove_person_and_organisation( the "person and organisation" group. :param person_and_organisation: The IfcPersonAndOrganization to remove. - :type person_and_organisation: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -46,17 +44,15 @@ def remove_person_and_organisation( ifcopenshell.api.owner.remove_person_and_organisation(model, person_and_organisation=user) """ - settings = {"person_and_organisation": person_and_organisation} - - for inverse in file.get_inverse(settings["person_and_organisation"]): + for inverse in file.get_inverse(person_and_organisation): if inverse.is_a("IfcDocumentInformation"): - if inverse.Editors == (settings["person_and_organisation"],): + if inverse.Editors == (person_and_organisation,): inverse.Editors = None elif inverse.is_a("IfcActor"): ifcopenshell.api.root.remove_product(file, product=inverse) elif inverse.is_a("IfcResourceLevelRelationship"): - if inverse.RelatedResourceObjects == (settings["person_and_organisation"],): + if inverse.RelatedResourceObjects == (person_and_organisation,): file.remove(inverse) elif inverse.is_a("IfcOwnerHistory"): file.remove(inverse) - file.remove(settings["person_and_organisation"]) + file.remove(person_and_organisation) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py index 07c2d36a9a..10c648cca5 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/remove_role.py @@ -25,9 +25,7 @@ def remove_role(file: ifcopenshell.file, role: ifcopenshell.entity_instance) -> leave some of them without roles. :param role: The IfcActorRole to remove. - :type role: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -40,13 +38,11 @@ def remove_role(file: ifcopenshell.file, role: ifcopenshell.entity_instance) -> # After running this, the organisation will have no role again ifcopenshell.api.owner.remove_role(model, role=role) """ - settings = {"role": role} - - for inverse in file.get_inverse(settings["role"]): + for inverse in file.get_inverse(role): if inverse.is_a() in ("IfcOrganization", "IfcPerson", "IfcPersonAndOrganization"): - if inverse.Roles == (settings["role"],): + if inverse.Roles == (role,): inverse.Roles = None elif inverse.is_a("IfcResourceLevelRelationship") and not inverse.is_a("IfcOrganizationRelationship"): - if inverse.RelatedResourceObjects == (settings["organisation"],): + if inverse.RelatedResourceObjects == (organisation,): file.remove(inverse) - file.remove(settings["role"]) + file.remove(role) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py b/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py index e161e046e2..98279c128d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/unassign_actor.py @@ -29,11 +29,8 @@ def unassign_actor( This means that the actor is no longer responsible for the object. :param relating_actor: The IfcActor who is responsible for the object. - :type relating_actor: ifcopenshell.entity_instance :param related_object: The object the actor is responsible for. - :type related_object: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -55,13 +52,8 @@ def unassign_actor( ifcopenshell.api.owner.unassign_actor(model, relating_actor=manufacturer, related_object=pump_type) """ - settings = { - "relating_actor": relating_actor, - "related_object": related_object, - } - - for rel in settings["related_object"].HasAssignments or []: - if not rel.is_a("IfcRelAssignsToActor") or rel.RelatingActor != settings["relating_actor"]: + for rel in related_object.HasAssignments or []: + if not rel.is_a("IfcRelAssignsToActor") or rel.RelatingActor != relating_actor: continue if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory @@ -70,6 +62,6 @@ def unassign_actor( ifcopenshell.util.element.remove_deep2(file, history) return related_objects = list(rel.RelatedObjects) - related_objects.remove(settings["related_object"]) + related_objects.remove(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) diff --git a/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py b/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py index c7cb3b719d..af40aa3b46 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py +++ b/src/ifcopenshell-python/ifcopenshell/api/owner/update_owner_history.py @@ -59,9 +59,6 @@ def update_owner_history( # API calls either. ifcopenshell.api.attribute.edit_attributes(model, product=space, attributes={"Name": "Lobby"}) """ - settings = {"element": element} - - element = settings["element"] if not element.is_a("IfcRoot"): return user = ifcopenshell.api.owner.settings.get_user(file) diff --git a/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py b/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py index 3a23507e54..97d8ba3f81 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py +++ b/src/ifcopenshell-python/ifcopenshell/api/profile/add_parameterized_profile.py @@ -30,9 +30,7 @@ def add_parameterized_profile(file: ifcopenshell.file, ifc_class: str) -> ifcope :param ifc_class: The subclass of IfcParameterizedProfileDef that you'd like to create. - :type ifc_class: str :return: The newly created element depending on the specified ifc_class. - :rtype: ifcopenshell.entity_instance Example: @@ -42,6 +40,4 @@ def add_parameterized_profile(file: ifcopenshell.file, ifc_class: str) -> ifcope ifc_class="IfcCircleProfileDef") circle.Radius = 1. """ - settings = {"ifc_class": ifc_class} - - return file.create_entity(settings["ifc_class"]) + return file.create_entity(ifc_class) diff --git a/src/ifcopenshell-python/ifcopenshell/api/profile/remove_profile.py b/src/ifcopenshell-python/ifcopenshell/api/profile/remove_profile.py index 5e3816fb93..be74271736 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/profile/remove_profile.py +++ b/src/ifcopenshell-python/ifcopenshell/api/profile/remove_profile.py @@ -35,11 +35,10 @@ def remove_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instanc circle = 1. ifcopenshell.api.profile.remove_profile(model, profile=circle) """ - settings = {"profile": profile} is_ifc2x3 = file.schema == "IFC2X3" subelements = set() - for attribute in settings["profile"]: + for attribute in profile: if isinstance(attribute, ifcopenshell.entity_instance): subelements.add(attribute) @@ -56,6 +55,6 @@ def remove_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instanc for pset in profile_psets: ifcopenshell.api.pset.remove_pset(file, product=profile, pset=pset) - file.remove(settings["profile"]) + file.remove(profile) for subelement in subelements: ifcopenshell.util.element.remove_deep2(file, subelement) diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/create_file.py b/src/ifcopenshell-python/ifcopenshell/api/project/create_file.py index 38da958ed5..6eaa324b82 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/create_file.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/create_file.py @@ -50,9 +50,7 @@ def create_file(version: ifcopenshell.util.schema.IFC_SCHEMA = "IFC4") -> ifcope # ... and off we go! """ - settings = {"version": version} - - file = ifcopenshell.file(schema=settings["version"]) + file = ifcopenshell.file(schema=version) file.wrapped_data.header.file_name.name = "/dev/null" # Hehehe file.wrapped_data.header.file_name.time_stamp = ( datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat() diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset/remove_pset.py b/src/ifcopenshell-python/ifcopenshell/api/pset/remove_pset.py index d6636e9f09..7c27dbd9bf 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset/remove_pset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset/remove_pset.py @@ -28,11 +28,8 @@ def remove_pset( All properties that are part of this property set are also removed. :param product: The IfcObject to remove the property set from. - :type product: ifcopenshell.entity_instance :param pset: The IfcPropertySet or IfcElementQuantity to remove. - :type pset: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -45,27 +42,25 @@ def remove_pset( # Remove it! ifcopenshell.api.pset.remove_pset(model, product=wall_type, pset=pset) """ - settings = {"product": product, "pset": pset} - to_purge = [] should_remove_pset = True - for inverse in file.get_inverse(settings["pset"]): + for inverse in file.get_inverse(pset): if inverse.is_a("IfcRelDefinesByProperties"): if not inverse.RelatedObjects or len(inverse.RelatedObjects) == 1: to_purge.append(inverse) else: related_objects = list(inverse.RelatedObjects) - related_objects.remove(settings["product"]) + related_objects.remove(product) inverse.RelatedObjects = related_objects should_remove_pset = False if should_remove_pset: properties = [] # Predefined psets have no properties - if settings["pset"].is_a("IfcPropertySet"): - properties = settings["pset"].HasProperties or [] - elif settings["pset"].is_a("IfcQuantitySet"): - properties = settings["pset"].Quantities or [] - elif settings["pset"].is_a() in ("IfcMaterialProperties", "IfcProfileProperties"): - properties = settings["pset"].Properties or [] + if pset.is_a("IfcPropertySet"): + properties = pset.HasProperties or [] + elif pset.is_a("IfcQuantitySet"): + properties = pset.Quantities or [] + elif pset.is_a() in ("IfcMaterialProperties", "IfcProfileProperties"): + properties = pset.Properties or [] for prop in properties: if file.get_total_inverses(prop) != 1: continue @@ -75,8 +70,8 @@ def remove_pset( file.remove(enumeration) file.remove(prop) # IfcMaterialProperties and IfcProfileProperties don't have OwnerHistory - history = getattr(settings["pset"], "OwnerHistory", None) - file.remove(settings["pset"]) + history = getattr(pset, "OwnerHistory", None) + file.remove(pset) if history: ifcopenshell.util.element.remove_deep2(file, history) for element in to_purge: diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_pset_template.py b/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_pset_template.py index fc1b9a4265..d66e5b2302 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_pset_template.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset_template/add_pset_template.py @@ -71,19 +71,15 @@ def add_pset_template( overridden by occurrences, and is applicable to everything. :param name: The name of the property set - :type name: str,optional :param template_type: Choose from one of PSET_TYPEDRIVENONLY, PSET_TYPEDRIVENOVERRIDE, PSET_OCCURRENCEDRIVEN, PSET_PERFORMANCEDRIVEN, QTO_TYPEDRIVENONLY, QTO_TYPEDRIVENOVERRIDE, QTO_OCCURRENCEDRIVEN, NOTDEFINED - :type template_type: str,optional :param applicable_entity: The entity that this template is allowed to be applied to. For example, IfcWall means that the property set may be assigned to walls only. IfcTypeObject, the default, means that the property set may be assigned to any type. - :type applicable_entity: str,optional :return: The newly created IfcPropertySetTemplate - :rtype: ifcopenshell.entity_instance Example: @@ -99,12 +95,10 @@ def add_pset_template( name="HighVoltage", description="Whether there is a risk of high voltage.", primary_measure_type="IfcBoolean") """ - settings = {"name": name, "template_type": template_type, "applicable_entity": applicable_entity} - return file.create_entity( "IfcPropertySetTemplate", GlobalId=ifcopenshell.guid.new(), - Name=settings["name"], - TemplateType=settings["template_type"], - ApplicableEntity=settings["applicable_entity"], + Name=name, + TemplateType=template_type, + ApplicableEntity=applicable_entity, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_prop_template.py b/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_prop_template.py index 99558cf6e8..ca8d5ba55e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_prop_template.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_prop_template.py @@ -27,9 +27,7 @@ def remove_prop_template(file: ifcopenshell.file, prop_template: ifcopenshell.en templates. :param prop_template: The IfcSimplePropertyTemplate to remove. - :type prop_template: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -44,13 +42,11 @@ def remove_prop_template(file: ifcopenshell.file, prop_template: ifcopenshell.en # Let's remove the second one. ifcopenshell.api.pset_template.remove_prop_template(model, prop_template=prop2) """ - settings = {"prop_template": prop_template} - - for inverse in file.get_inverse(settings["prop_template"]): + for inverse in file.get_inverse(prop_template): if len(inverse.HasPropertyTemplates) == 1: inverse.HasPropertyTemplates = [] else: has_property_templates = list(inverse.HasPropertyTemplates) - has_property_templates.remove(settings["prop_template"]) + has_property_templates.remove(prop_template) inverse.HasPropertyTemplates = has_property_templates - ifcopenshell.util.element.remove_deep(file, settings["prop_template"]) + ifcopenshell.util.element.remove_deep(file, prop_template) diff --git a/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_pset_template.py b/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_pset_template.py index de321ea6fd..07d5cf6daf 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_pset_template.py +++ b/src/ifcopenshell-python/ifcopenshell/api/pset_template/remove_pset_template.py @@ -26,9 +26,7 @@ def remove_pset_template(file: ifcopenshell.file, pset_template: ifcopenshell.en along with it. :param pset_template: The IfcPropertySetTemplate to remove. - :type pset_template: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -40,6 +38,4 @@ def remove_pset_template(file: ifcopenshell.file, pset_template: ifcopenshell.en # Let's remove the template. ifcopenshell.api.pset_template.remove_pset_template(model, pset_template=template) """ - settings = {"pset_template": pset_template} - - ifcopenshell.util.element.remove_deep(file, settings["pset_template"]) + ifcopenshell.util.element.remove_deep(file, pset_template) diff --git a/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource.py b/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource.py index 41aa8bec8c..691ad2ec6a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource.py +++ b/src/ifcopenshell-python/ifcopenshell/api/resource/add_resource.py @@ -51,20 +51,15 @@ def add_resource( :param parent_resource: If this is a child resource (typically to a crew resource), then nominate the parent IfcConstructionResource here. - :type parent_resource: ifcopenshell.entity_instance, optional :param ifc_class: The class of resource chosen from IfcConstructionEquipmentResource, IfcConstructionMaterialResource, IfcConstructionProductResource, IfcCrewResource, IfcLaborResource, or IfcSubContractResource. - :type ifc_class: str,optional :param name: The name of the resource - :type name: str,optional :param predefined_type: Consult the IFC documentation for the valid predefined types for each type of resource class. - :type predefined_type: str,optional :return: The newly created resource depending on the nominated IFC class. - :rtype: ifcopenshell.entity_instance Example: @@ -76,25 +71,17 @@ def add_resource( # Add some labour to our crew. ifcopenshell.api.resource.add_resource(model, parent_resource=crew, ifc_class="IfcLaborResource") """ - settings = { - "parent_resource": parent_resource, - "ifc_class": ifc_class, - "name": name, - "predefined_type": predefined_type, - } resource = ifcopenshell.api.root.create_entity( file, - ifc_class=settings["ifc_class"], - predefined_type=settings["predefined_type"], - name=settings["name"] or "Unnamed", + ifc_class=ifc_class, + predefined_type=predefined_type, + name=name or "Unnamed", ) # TODO: this is an ambiguity by buildingSMART: Can we nest an IfcCrewResource under an IfcCrewResource ? # https://forums.buildingsmart.org/t/what-are-allowed-to-be-root-level-construction-resources/3550 - if settings["parent_resource"]: - ifcopenshell.api.nest.assign_object( - file, related_objects=[resource], relating_object=settings["parent_resource"] - ) + if parent_resource: + ifcopenshell.api.nest.assign_object(file, related_objects=[resource], relating_object=parent_resource) elif file.schema != "IFC2X3": context = file.by_type("IfcContext")[0] ifcopenshell.api.project.assign_declaration(file, definitions=[resource], relating_context=context) diff --git a/src/ifcopenshell-python/ifcopenshell/api/resource/assign_resource.py b/src/ifcopenshell-python/ifcopenshell/api/resource/assign_resource.py index 626082bce2..618d10895a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/resource/assign_resource.py +++ b/src/ifcopenshell-python/ifcopenshell/api/resource/assign_resource.py @@ -42,12 +42,9 @@ def assign_resource( (e.g. if the resource is a labour resource). :param relating_resource: The IfcResource to assign the object to. - :type relating_resource: ifcopenshell.entity_instance :param related_object: The IfcProduct or IfcActor to assign to the object. - :type related_object: ifcopenshell.entity_instance :return: The newly created IfcRelAssignsToResource - :rtype: ifcopenshell.entity_instance Example: @@ -82,26 +79,18 @@ def assign_resource( # This means that UCO is now our crane operator. ifcopenshell.api.resource.assign_resource(model, relating_resource=crane, related_object=actor) """ - settings = { - "relating_resource": relating_resource, - "related_object": related_object, - } - - if settings["related_object"].HasAssignments: - for assignment in settings["related_object"].HasAssignments: - if ( - assignment.is_a("IfclRelAssignsToResource") - and assignment.RelatingResource == settings["relating_resource"] - ): + if related_object.HasAssignments: + for assignment in related_object.HasAssignments: + if assignment.is_a("IfclRelAssignsToResource") and assignment.RelatingResource == relating_resource: return assignment resource_of = None - if settings["relating_resource"].ResourceOf: - resource_of = settings["relating_resource"].ResourceOf[0] + if relating_resource.ResourceOf: + resource_of = relating_resource.ResourceOf[0] if resource_of: related_objects = list(resource_of.RelatedObjects) - related_objects.append(settings["related_object"]) + related_objects.append(related_object) resource_of.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": resource_of}) else: @@ -110,8 +99,8 @@ def assign_resource( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": [settings["related_object"]], - "RelatingResource": settings["relating_resource"], + "RelatedObjects": [related_object], + "RelatingResource": relating_resource, } ) return resource_of diff --git a/src/ifcopenshell-python/ifcopenshell/api/resource/calculate_resource_usage.py b/src/ifcopenshell-python/ifcopenshell/api/resource/calculate_resource_usage.py index 0a68a83df4..545016bfd2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/resource/calculate_resource_usage.py +++ b/src/ifcopenshell-python/ifcopenshell/api/resource/calculate_resource_usage.py @@ -25,15 +25,18 @@ import ifcopenshell.util.resource def calculate_resource_usage(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> None: - """Calculates the number of resources required to perform scheduled work on a task.""" - settings = {"resource": resource} + """Calculates the number of resources required to perform scheduled work on a task. - if ifcopenshell.util.constraint.is_attribute_locked(settings["resource"], "Usage.ScheduleUsage"): + :param resource: The IfcConstructionResource to calculate the usage for. + :return: None + """ + + if ifcopenshell.util.constraint.is_attribute_locked(resource, "Usage.ScheduleUsage"): return - if not settings["resource"].Usage or not settings["resource"].Usage.ScheduleWork: + if not resource.Usage or not resource.Usage.ScheduleWork: return - task = ifcopenshell.util.resource.get_task_assignments(settings["resource"]) + task = ifcopenshell.util.resource.get_task_assignments(resource) if not task or not task.TaskTime: return @@ -46,7 +49,7 @@ def calculate_resource_usage(file: ifcopenshell.file, resource: ifcopenshell.ent seconds = task_duration.days * hours_per_day * 60 * 60 seconds += task_duration.seconds - person_hours = ifcopenshell.util.date.ifc2datetime(settings["resource"].Usage.ScheduleWork) + person_hours = ifcopenshell.util.date.ifc2datetime(resource.Usage.ScheduleWork) required_resources = person_hours.total_seconds() / seconds - settings["resource"].Usage.ScheduleUsage = float(required_resources) + resource.Usage.ScheduleUsage = float(required_resources) diff --git a/src/ifcopenshell-python/ifcopenshell/api/resource/remove_resource_quantity.py b/src/ifcopenshell-python/ifcopenshell/api/resource/remove_resource_quantity.py index e7c91e6073..a6b014e1db 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/resource/remove_resource_quantity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/resource/remove_resource_quantity.py @@ -22,6 +22,9 @@ import ifcopenshell.util.element def remove_resource_quantity(file: ifcopenshell.file, resource: ifcopenshell.entity_instance) -> None: """Removes the base quantity of a resource + :param resource: The IfcConstructionResource to remove the quantity from. + :return: None + Example: .. code:: python @@ -41,9 +44,7 @@ def remove_resource_quantity(file: ifcopenshell.file, resource: ifcopenshell.ent # let's clean up our mess and remove the quantity. ifcopenshell.api.resource.remove_resource_quantity(model, resource=labour) """ - settings = {"resource": resource} - - old_quantity = settings["resource"].BaseQuantity - settings["resource"].BaseQuantity = None + old_quantity = resource.BaseQuantity + resource.BaseQuantity = None if old_quantity: ifcopenshell.util.element.remove_deep(file, old_quantity) diff --git a/src/ifcopenshell-python/ifcopenshell/api/resource/unassign_resource.py b/src/ifcopenshell-python/ifcopenshell/api/resource/unassign_resource.py index 76ea9e6d5b..dc0807754d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/resource/unassign_resource.py +++ b/src/ifcopenshell-python/ifcopenshell/api/resource/unassign_resource.py @@ -29,12 +29,9 @@ def unassign_resource( """Removes the relationship between a resource and object :param relating_resource: The IfcResource to assign the object to. - :type relating_resource: ifcopenshell.entity_instance :param related_object: The IfcProduct or IfcActor to assign to the object. - :type related_object: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -60,13 +57,8 @@ def unassign_resource( ifcopenshell.api.resource.unassign_resource(model, relating_resource=crane, related_object=product) """ - settings = { - "relating_resource": relating_resource, - "related_object": related_object, - } - - for rel in settings["related_object"].HasAssignments or []: - if not rel.is_a("IfcRelAssignsToResource") or rel.RelatingResource != settings["relating_resource"]: + for rel in related_object.HasAssignments or []: + if not rel.is_a("IfcRelAssignsToResource") or rel.RelatingResource != relating_resource: continue if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory @@ -75,6 +67,6 @@ def unassign_resource( ifcopenshell.util.element.remove_deep2(file, history) return related_objects = list(rel.RelatedObjects) - related_objects.remove(settings["related_object"]) + related_objects.remove(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py b/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py index 67d67ed7f2..ad44cede8d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py @@ -71,48 +71,44 @@ def create_entity( """ usecase = Usecase() usecase.file = file - usecase.settings = { - "ifc_class": ifc_class, - "predefined_type": predefined_type, - "name": name, - } - return usecase.execute() + return usecase.execute(ifc_class, predefined_type, name) class Usecase: file: ifcopenshell.file - settings: dict[str, Any] - def execute(self): + def execute( + self, ifc_class: str, predefined_type: Optional[str] = None, name: Optional[str] = None + ) -> ifcopenshell.entity_instance: element = self.file.create_entity( - self.settings["ifc_class"], + ifc_class, **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(self.file), } ) - element.Name = self.settings["name"] or None - if self.settings["predefined_type"]: + element.Name = name or None + if predefined_type: if hasattr(element, "PredefinedType"): try: - element.PredefinedType = self.settings["predefined_type"] + element.PredefinedType = predefined_type except: element.PredefinedType = "USERDEFINED" if hasattr(element, "ObjectType"): - element.ObjectType = self.settings["predefined_type"] + element.ObjectType = predefined_type elif hasattr(element, "ElementType"): - element.ElementType = self.settings["predefined_type"] + element.ElementType = predefined_type elif hasattr(element, "ProcessType"): - element.ProcessType = self.settings["predefined_type"] + element.ProcessType = predefined_type elif hasattr(element, "ObjectType"): - element.ObjectType = self.settings["predefined_type"] + element.ObjectType = predefined_type if self.file.schema == "IFC2X3": self.handle_2x3_defaults(element) else: self.handle_4_defaults(element) return element - def handle_2x3_defaults(self, element): + def handle_2x3_defaults(self, element: ifcopenshell.entity_instance) -> None: if element.is_a("IfcElementType"): if hasattr(element, "PredefinedType") and not element.PredefinedType: element.PredefinedType = "NOTDEFINED" @@ -129,7 +125,7 @@ class Usecase: element.ParameterTakesPrecedence = False element.Sizeable = False - def handle_4_defaults(self, element): + def handle_4_defaults(self, element: ifcopenshell.entity_instance) -> None: if element.is_a("IfcElementType"): if hasattr(element, "PredefinedType") and not element.PredefinedType: element.PredefinedType = "NOTDEFINED" diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py index 1e1b4fe2df..f6fa8feb8e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_task.py @@ -69,23 +69,16 @@ def add_task( :param work_schedule: The work schedule to group the task in, if the task is to be a top-level or root task. This is mutually exclusive with the parent_task parameter. - :type work_schedule: ifcopenshell.entity_instance, optional :param parent_task: The parent task, if the task is to be a subtask or child task. This is mutually exclusive with the work_schedule parameter. - :type parent_task: ifcopenshell.entity_instance, optioanl :param name: The name of the task. - :type name: str,optional :param description: The description of the task. - :type description: str,optional :param identification: The identification code of the task. - :type identification: str,optional :param predefined_type: The predefined type of the task. Common ones include CONSTRUCTION, DEMOLITION, or MAINTENANCE. Consultant the IFC documentation for IfcTaskTypeEnum for more information. - :type predefined_type: str :return: The newly created IfcTask - :rtype: ifcopenshell.entity_instance Example: @@ -139,39 +132,28 @@ def add_task( ifcopenshell.api.sequence.add_task(model, parent_task=cleaning, identification="3", description="Setup the water pressure by tapping to a water supply and connecting to a ...") """ - settings = { - "work_schedule": work_schedule, - "parent_task": parent_task, - "name": name, - "description": description, - "identification": identification, - "predefined_type": predefined_type, - } - - task = ifcopenshell.api.root.create_entity( - file, ifc_class="IfcTask", name=settings["name"], predefined_type=settings["predefined_type"] - ) - if settings["description"]: - task.Description = settings["description"] - if settings["identification"]: - task.Identification = settings["identification"] + task = ifcopenshell.api.root.create_entity(file, ifc_class="IfcTask", name=name, predefined_type=predefined_type) + if description: + task.Description = description + if identification: + task.Identification = identification task.IsMilestone = False - if settings["work_schedule"]: + if work_schedule: file.create_entity( "IfcRelAssignsToControl", **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), "RelatedObjects": [task], - "RelatingControl": settings["work_schedule"], + "RelatingControl": work_schedule, } ) - elif settings["parent_task"]: + elif parent_task: rel = ifcopenshell.api.nest.assign_object( file, related_objects=[task], - relating_object=settings["parent_task"], + relating_object=parent_task, ) - if file.schema != "IFC2X3" and settings["parent_task"].Identification: - task.Identification = settings["parent_task"].Identification + "." + str(len(rel.RelatedObjects)) + if file.schema != "IFC2X3" and parent_task.Identification: + task.Identification = parent_task.Identification + "." + str(len(rel.RelatedObjects)) return task diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_time_period.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_time_period.py index 28814da438..41e0785b1d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_time_period.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_time_period.py @@ -44,17 +44,13 @@ def add_time_period( :param recurrence_pattern: The IfcRecurrencePattern to add the time period to. See ifcopenshell.api.sequence.assign_recurrence_pattern. - :type recurrence_pattern: ifcopenshell.entity_instance :param start_time: The start time of the time period, in a format compatible with IfcTime, such as an ISO format time string or a datetime.time object. - :type start_time: str,datetime.time :param end_time: The end time of the time period, in a format compatible with IfcTime, such as an ISO format time string or a datetime.time object. - :type end_time: str,datetime.time :return: The newly created IfcTimePeriod - :rtype: ifcopenshell.entity_instance Example: @@ -81,18 +77,12 @@ def add_time_period( ifcopenshell.api.sequence.add_time_period(model, recurrence_pattern=pattern, start_time="13:00", end_time="17:00") """ - settings = { - "recurrence_pattern": recurrence_pattern, - "start_time": start_time, - "end_time": end_time, - } - time_period = file.create_entity("IfcTimePeriod") - time_period.StartTime = ifcopenshell.util.date.datetime2ifc(settings["start_time"], "IfcTime") - time_period.EndTime = ifcopenshell.util.date.datetime2ifc(settings["end_time"], "IfcTime") - time_periods = list(settings["recurrence_pattern"].TimePeriods or []) + time_period.StartTime = ifcopenshell.util.date.datetime2ifc(start_time, "IfcTime") + time_period.EndTime = ifcopenshell.util.date.datetime2ifc(end_time, "IfcTime") + time_periods = list(recurrence_pattern.TimePeriods or []) time_periods.append(time_period) - settings["recurrence_pattern"].TimePeriods = time_periods + recurrence_pattern.TimePeriods = time_periods ifcopenshell.util.sequence.is_working_day.cache_clear() ifcopenshell.util.sequence.is_calendar_applicable.cache_clear() diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_calendar.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_calendar.py index e4af1d88b2..254188dcd8 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_calendar.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_calendar.py @@ -38,12 +38,10 @@ def add_work_calendar( :param name: The name of the calendar. Typically something like "5 Day Working Week" or "24/7". - :type name: str, optional :param predefined_type: The type of calendar, typically used to more specifically define shifts, such as FIRSTSHIFT, SECONDSHIFT, or THIRDSHIFT. Leave as NOTDEFINED for basic calendar usage. :return: The newly created IfcWorkCalendar - :rtype: ifcopenshell.entity_instance Example: @@ -79,13 +77,11 @@ def add_work_calendar( # this calendar by default (though you can override them). ifcopenshell.api.control.assign_control(model, relating_control=calendar, related_object=task) """ - settings = {"name": name, "predefined_type": predefined_type} - work_calendar = ifcopenshell.api.root.create_entity( file, ifc_class="IfcWorkCalendar", - predefined_type=settings["predefined_type"], - name=settings["name"], + predefined_type=predefined_type, + name=name, ) context = file.by_type("IfcContext")[0] ifcopenshell.api.project.assign_declaration( diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py index 0bd53cb14f..2cb4f05ec6 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_plan.py @@ -41,15 +41,11 @@ def add_work_plan( :param name: The name of the work plan. Recommended to be "Maintenance" or "Construction" for the two main purposes. - :type name: str, optional :param predefined_type: The type of work plan, used for baselining. Leave as "NOTDEFINED" if unsure. - :type predefined_type: str :param start_time: The earliest start time when the schedules grouped within the work plan are relevant. - :type start_time: str,datetime.time :return: The newly created IfcWorkPlan - :rtype: ifcopenshell.entity_instance Example: @@ -62,23 +58,18 @@ def add_work_plan( schedule = ifcopenshell.api.sequence.add_work_schedule(model, name="Construction Schedule A", work_plan=work_plan) """ - settings = { - "name": name, - "predefined_type": predefined_type, - "start_time": start_time or datetime.now(), - } - + start_time = start_time or datetime.now() work_plan = ifcopenshell.api.root.create_entity( file, ifc_class="IfcWorkPlan", - predefined_type=settings["predefined_type"], - name=settings["name"], + predefined_type=predefined_type, + name=name, ) work_plan.CreationDate = ifcopenshell.util.date.datetime2ifc(datetime.now(), "IfcDateTime") user = ifcopenshell.api.owner.settings.get_user(file) if user: work_plan.Creators = [user.ThePerson] - work_plan.StartTime = ifcopenshell.util.date.datetime2ifc(settings["start_time"], "IfcDateTime") + work_plan.StartTime = ifcopenshell.util.date.datetime2ifc(start_time, "IfcDateTime") context = file.by_type("IfcContext")[0] ifcopenshell.api.project.assign_declaration( diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_schedule.py index 4bdc77b955..d81998021b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_schedule.py @@ -77,19 +77,12 @@ def add_work_schedule( construction = ifcopenshell.api.sequence.add_task(model, work_schedule=schedule, name="Construction", identification="C") """ - settings = { - "name": name, - "predefined_type": predefined_type, - "object_type": object_type, - "start_time": start_time or datetime.now(), - "work_plan": work_plan, - } - + start_time = start_time or datetime.now() work_schedule = ifcopenshell.api.root.create_entity( file, ifc_class="IfcWorkSchedule", - predefined_type=settings["predefined_type"], - name=settings["name"], + predefined_type=predefined_type, + name=name, ) if file.schema == "IFC2X3": work_schedule.CreationDate = createIfcDateAndTime(file, datetime.now()) @@ -99,17 +92,17 @@ def add_work_schedule( if user: work_schedule.Creators = [user.ThePerson] if file.schema == "IFC2X3": - work_schedule.StartTime = createIfcDateAndTime(file, settings["start_time"]) + work_schedule.StartTime = createIfcDateAndTime(file, start_time) else: - work_schedule.StartTime = ifcopenshell.util.date.datetime2ifc(settings["start_time"], "IfcDateTime") - if settings["object_type"]: - work_schedule.ObjectType = settings["object_type"] - if settings["work_plan"]: + work_schedule.StartTime = ifcopenshell.util.date.datetime2ifc(start_time, "IfcDateTime") + if object_type: + work_schedule.ObjectType = object_type + if work_plan: ifcopenshell.api.aggregate.assign_object( file, **{ "products": [work_schedule], - "relating_object": settings["work_plan"], + "relating_object": work_plan, } ) elif file.schema != "IFC2X3": diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_time.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_time.py index af55e01a2e..05b4960e09 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_time.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/add_work_time.py @@ -36,12 +36,9 @@ def add_work_time( :param work_calendar: The IfcWorkCalendar to add the work or holiday time definition to. - :type work_calendar: ifcopenshell.entity_instance :param time_type: Either WorkingTimes or ExceptionTimes, depending on what you want to define. - :type time_type: str :return: The newly created IfcWorkTime - :rtype: ifcopenshell.entity_instance Example: @@ -74,15 +71,13 @@ def add_work_time( ifcopenshell.api.sequence.edit_recurrence_pattern(model, recurrence_pattern=pattern, attributes={"DayComponent": [1], "MonthComponent": [1]}) """ - settings = {"work_calendar": work_calendar, "time_type": time_type} - work_time = file.create_entity("IfcWorkTime") - if settings["time_type"] == "WorkingTimes": - working_times = list(settings["work_calendar"].WorkingTimes or []) + if time_type == "WorkingTimes": + working_times = list(work_calendar.WorkingTimes or []) working_times.append(work_time) - settings["work_calendar"].WorkingTimes = working_times - elif settings["time_type"] == "ExceptionTimes": - exception_times = list(settings["work_calendar"].ExceptionTimes or []) + work_calendar.WorkingTimes = working_times + elif time_type == "ExceptionTimes": + exception_times = list(work_calendar.ExceptionTimes or []) exception_times.append(work_time) - settings["work_calendar"].ExceptionTimes = exception_times + work_calendar.ExceptionTimes = exception_times return work_time diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_process.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_process.py index fac605ac40..238e9eedc2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_process.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_process.py @@ -65,12 +65,9 @@ def assign_process( :param relating_process: The IfcProcess (typically IfcTask) that the input, control, or resource is related to. - :type relating_process: ifcopenshell.entity_instance :param related_object: The IfcProduct (for input), IfcCostItem (for control) or IfcConstructionResource (for resource). - :type related_object: ifcopenshell.entity_instance :return: The newly created IfcRelAssignsToProcess relationship - :rtype: ifcopenshell.entity_instance Example: @@ -91,23 +88,18 @@ def assign_process( # Let's demolish that wall! ifcopenshell.api.sequence.assign_process(model, relating_process=task, related_object=wall) """ - settings = { - "relating_process": relating_process, - "related_object": related_object, - } - - if settings["related_object"].HasAssignments: - for assignment in settings["related_object"].HasAssignments: - if assignment.is_a("IfcRelAssignsToProcess") and assignment.RelatingProcess == settings["relating_process"]: + if related_object.HasAssignments: + for assignment in related_object.HasAssignments: + if assignment.is_a("IfcRelAssignsToProcess") and assignment.RelatingProcess == relating_process: return operates_on = None - if settings["relating_process"].OperatesOn: - operates_on = settings["relating_process"].OperatesOn[0] + if relating_process.OperatesOn: + operates_on = relating_process.OperatesOn[0] if operates_on: related_objects = list(operates_on.RelatedObjects) - related_objects.append(settings["related_object"]) + related_objects.append(related_object) operates_on.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": operates_on}) else: @@ -116,8 +108,8 @@ def assign_process( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": [settings["related_object"]], - "RelatingProcess": settings["relating_process"], + "RelatedObjects": [related_object], + "RelatingProcess": relating_process, } ) return operates_on diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_product.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_product.py index 65971cdae4..8a657302b5 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_product.py @@ -41,12 +41,9 @@ def assign_product( :param relating_product: The IfcProduct that was constructed as a result of the task. - :type relating_product: ifcopenshell.entity_instance :param related_object: The IfcProcess (typically IfcTask) of the construction task. - :type related_object: ifcopenshell.entity_instance :return: The newly created IfcRelAssignsToProduct relationship - :rtype: ifcopenshell.entity_instance Example: @@ -67,23 +64,18 @@ def assign_product( # Let's construct that wall! ifcopenshell.api.sequence.assign_product(model, relating_product=wall, related_object=task) """ - settings = { - "relating_product": relating_product, - "related_object": related_object, - } - - if settings["related_object"].HasAssignments: - for assignment in settings["related_object"].HasAssignments: - if assignment.is_a("IfcRelAssignsToProduct") and assignment.RelatingProduct == settings["relating_product"]: + if related_object.HasAssignments: + for assignment in related_object.HasAssignments: + if assignment.is_a("IfcRelAssignsToProduct") and assignment.RelatingProduct == relating_product: return assignment referenced_by = None - if settings["relating_product"].ReferencedBy: - referenced_by = settings["relating_product"].ReferencedBy[0] + if relating_product.ReferencedBy: + referenced_by = relating_product.ReferencedBy[0] if referenced_by: related_objects = list(referenced_by.RelatedObjects) - related_objects.append(settings["related_object"]) + related_objects.append(related_object) referenced_by.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, **{"element": referenced_by}) else: @@ -92,8 +84,8 @@ def assign_product( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedObjects": [settings["related_object"]], - "RelatingProduct": settings["relating_product"], + "RelatedObjects": [related_object], + "RelatingProduct": relating_product, } ) return referenced_by diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_work_plan.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_work_plan.py index 0a32b9d580..4b2fd704f4 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_work_plan.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/assign_work_plan.py @@ -19,11 +19,12 @@ import ifcopenshell import ifcopenshell.api.project import ifcopenshell.api.aggregate +from typing import Union def assign_work_plan( file: ifcopenshell.file, work_schedule: ifcopenshell.entity_instance, work_plan: ifcopenshell.entity_instance -) -> ifcopenshell.entity_instance: +) -> Union[ifcopenshell.entity_instance, None]: """Assigns a work schedule to a work plan Typically, work schedules would be assigned to a work plan at creation. @@ -31,11 +32,8 @@ def assign_work_plan( :param work_schedule: The IfcWorkSchedule that will be assigned to the work plan. - :type work_schedule: ifcopenshell.entity_instance :param work_plan: The IfcWorkPlan for the schedule to be assigned to. - :type work_plan: ifcopenshell.entity_instance :return: The IfcRelAggregates relationship - :rtype: ifcopenshell.entity_instance Example: @@ -50,20 +48,16 @@ def assign_work_plan( # ... you can assign the work plan afterwards. ifcopenshell.api.sequence.assign_work_plan(work_schedule=schedule, work_plan=work_plan) """ - settings = {"work_schedule": work_schedule, "work_plan": work_plan} - # TODO: this is an ambiguity by buildingSMART # See https://forums.buildingsmart.org/t/is-the-ifcworkschedule-project-declaration-mutually-exclusive-to-aggregation-within-a-relating-ifcworkplan/3510 ifcopenshell.api.project.unassign_declaration( file, - definitions=[settings["work_schedule"]], + definitions=[work_schedule], relating_context=file.by_type("IfcContext")[0], ) rel_aggregates = ifcopenshell.api.aggregate.assign_object( file, - **{ - "products": [settings["work_schedule"]], - "relating_object": settings["work_plan"], - } + products=[work_schedule], + relating_object=work_plan, ) return rel_aggregates diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/duplicate_task.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/duplicate_task.py index 7f974bb84e..a70868b084 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/duplicate_task.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/duplicate_task.py @@ -21,6 +21,7 @@ import ifcopenshell.guid import ifcopenshell.api.nest import ifcopenshell.api.owner import ifcopenshell.api.sequence +import ifcopenshell.util.date import ifcopenshell.util.element import ifcopenshell.util.sequence from typing import Union, Any @@ -155,7 +156,9 @@ class Usecase: duration_type=inverse.TimeLag.DurationType, ) - def create_object_reference(self, relating_object, related_object): + def create_object_reference( + self, relating_object: ifcopenshell.entity_instance, related_object: ifcopenshell.entity_instance + ) -> ifcopenshell.entity_instance: referenced_by = None if relating_object.Declares: referenced_by = relating_object.Declares[0] diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py index 9af73898ea..107dcada2b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_task.py @@ -31,9 +31,7 @@ def remove_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance) -> sequences or controls are also removed. :param task: The IfcTask to remove. - :type task: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -56,76 +54,74 @@ def remove_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance) -> # just fix it on site. ifcopenshell.api.sequence.remove_task(model, task=design) """ - settings = {"task": task} - # TODO: do a deep purge ifcopenshell.api.project.unassign_declaration( file, - definitions=[settings["task"]], + definitions=[task], relating_context=file.by_type("IfcContext")[0], ) - if task_time := settings["task"].TaskTime: + if task_time := task.TaskTime: if task_time.is_a("IfcTaskTimeRecurring"): ifcopenshell.api.sequence.unassign_recurrence_pattern(file, task_time.Recurrence) file.remove(task_time) # Handle IfcRelNests. - if rels := settings["task"].IsNestedBy: + if rels := task.IsNestedBy: subtasks = rels[0].RelatedObjects # Use batching for optimization. ifcopenshell.api.nest.unassign_object(file, subtasks) for task_ in subtasks: ifcopenshell.api.sequence.remove_task(file, task=task_) - if settings["task"].Nests: - ifcopenshell.api.nest.unassign_object(file, [settings["task"]]) + if task.Nests: + ifcopenshell.api.nest.unassign_object(file, [task]) - for inverse in file.get_inverse(settings["task"]): + for inverse in file.get_inverse(task): if inverse.is_a("IfcRelSequence"): history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) elif inverse.is_a("IfcRelAssignsToControl"): - if inverse.RelatingControl == settings["task"] or len(inverse.RelatedObjects) == 1: + if inverse.RelatingControl == task or len(inverse.RelatedObjects) == 1: history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) else: related_objects = list(inverse.RelatedObjects) - related_objects.remove(settings["task"]) + related_objects.remove(task) inverse.RelatedObjects = related_objects elif inverse.is_a("IfcRelDefinesByProperties"): ifcopenshell.api.pset.remove_pset( file, - product=settings["task"], + product=task, pset=inverse.RelatingPropertyDefinition, ) elif inverse.is_a("IfcRelAssignsToProcess"): - if inverse.RelatingProcess == settings["task"] or len(inverse.RelatedObjects) == 1: + if inverse.RelatingProcess == task or len(inverse.RelatedObjects) == 1: history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) elif inverse.is_a("IfcRelAssignsToProduct"): - if inverse.RelatingProduct == settings["task"] or len(inverse.RelatedObjects) == 1: + if inverse.RelatingProduct == task or len(inverse.RelatedObjects) == 1: history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) else: related_objects = list(inverse.RelatedObjects) - related_objects.remove(settings["task"]) + related_objects.remove(task) inverse.RelatedObjects = related_objects elif inverse.is_a("IfcRelAssignsToObject"): - if inverse.RelatingObject == settings["task"] or len(inverse.RelatedObjects) == 1: + if inverse.RelatingObject == task or len(inverse.RelatedObjects) == 1: history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) else: related_objects = list(inverse.RelatedObjects) - related_objects.remove(settings["task"]) + related_objects.remove(task) inverse.RelatedObjects = related_objects elif inverse.is_a("IfcRelAssignsToProcess"): history = inverse.OwnerHistory @@ -133,7 +129,7 @@ def remove_task(file: ifcopenshell.file, task: ifcopenshell.entity_instance) -> if history: ifcopenshell.util.element.remove_deep2(file, history) - history = settings["task"].OwnerHistory - file.remove(settings["task"]) + history = task.OwnerHistory + file.remove(task) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_time_period.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_time_period.py index 247323c04a..50314f8362 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_time_period.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_time_period.py @@ -23,9 +23,7 @@ def remove_time_period(file: ifcopenshell.file, time_period: ifcopenshell.entity """Removes a time period :param time_period: The IfcTimePeriod to remove. - :type time_period: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -55,6 +53,4 @@ def remove_time_period(file: ifcopenshell.file, time_period: ifcopenshell.entity # Let's take the afternoon off! ifcopenshell.api.sequence.remove_time_period(model, time_period=afternoon) """ - settings = {"time_period": time_period} - - file.remove(settings["time_period"]) + file.remove(time_period) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_calendar.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_calendar.py index 27213630e5..0ff9c5109d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_calendar.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_calendar.py @@ -30,9 +30,7 @@ def remove_work_calendar(file: ifcopenshell.file, work_calendar: ifcopenshell.en calendar. :param work_calendar: The IfcWorkCalendar to remove - :type work_calendar: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -44,32 +42,30 @@ def remove_work_calendar(file: ifcopenshell.file, work_calendar: ifcopenshell.en # And remove it immediately ifcopenshell.api.sequence.remove_work_calendar(model, work_calendar=calendar) """ - settings = {"work_calendar": work_calendar} - # TODO: do a deep purge ifcopenshell.api.project.unassign_declaration( file, - definitions=[settings["work_calendar"]], + definitions=[work_calendar], relating_context=file.by_type("IfcContext")[0], ) - if settings["work_calendar"].Controls: - for rel in settings["work_calendar"].Controls: + if work_calendar.Controls: + for rel in work_calendar.Controls: for related_object in rel.RelatedObjects: ifcopenshell.api.control.unassign_control( file, - relating_control=settings["work_calendar"], + relating_control=work_calendar, related_object=related_object, ) # Currently in API work times are created already attached # to the work calendar, so they are never reused. - for working_time in settings["work_calendar"].WorkingTimes or []: + for working_time in work_calendar.WorkingTimes or []: ifcopenshell.api.sequence.remove_work_time(file, work_time=working_time) - for exception_time in settings["work_calendar"].ExceptionTimes or []: + for exception_time in work_calendar.ExceptionTimes or []: ifcopenshell.api.sequence.remove_work_time(file, work_time=exception_time) - history = settings["work_calendar"].OwnerHistory - file.remove(settings["work_calendar"]) + history = work_calendar.OwnerHistory + file.remove(work_calendar) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py index 4f655fbd0c..1d7fd8ce3a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_plan.py @@ -29,9 +29,7 @@ def remove_work_plan(file: ifcopenshell.file, work_plan: ifcopenshell.entity_ins removed. :param work_plan: The IfcWorkPlan to remove. - :type work_plan: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -43,11 +41,9 @@ def remove_work_plan(file: ifcopenshell.file, work_plan: ifcopenshell.entity_ins # And remove it immediately ifcopenshell.api.sequence.remove_work_plan(model, work_plan=work_plan) """ - settings = {"work_plan": work_plan} - ifcopenshell.api.project.unassign_declaration( file, - definitions=[settings["work_plan"]], + definitions=[work_plan], relating_context=file.by_type("IfcContext")[0], ) @@ -55,7 +51,7 @@ def remove_work_plan(file: ifcopenshell.file, work_plan: ifcopenshell.entity_ins if related_objects: ifcopenshell.api.aggregate.unassign_object(file, related_objects) - history = settings["work_plan"].OwnerHistory - file.remove(settings["work_plan"]) + history = work_plan.OwnerHistory + file.remove(work_plan) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py index d14258e6ec..5304ac64ad 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/remove_work_schedule.py @@ -47,32 +47,30 @@ def remove_work_schedule(file: ifcopenshell.file, work_schedule: ifcopenshell.en # And remove it immediately ifcopenshell.api.sequence.remove_work_schedule(model, work_schedule=schedule) """ - settings = {"work_schedule": work_schedule} - # TODO: do a deep purge ifcopenshell.api.project.unassign_declaration( - file, definitions=[settings["work_schedule"]], relating_context=file.by_type("IfcContext")[0] + file, definitions=[work_schedule], relating_context=file.by_type("IfcContext")[0] ) - if settings["work_schedule"].Declares: - for rel in settings["work_schedule"].Declares: - for work_schedule in rel.RelatedObjects: - ifcopenshell.api.sequence.remove_work_schedule(file, work_schedule=work_schedule) + if work_schedule.Declares: + for rel in work_schedule.Declares: + for work_schedule_ in rel.RelatedObjects: + ifcopenshell.api.sequence.remove_work_schedule(file, work_schedule=work_schedule_) # Unassign from work plans. - if settings["work_schedule"].Decomposes: - ifcopenshell.api.aggregate.unassign_object(file, [settings["work_schedule"]]) + if work_schedule.Decomposes: + ifcopenshell.api.aggregate.unassign_object(file, [work_schedule]) - for inverse in file.get_inverse(settings["work_schedule"]): + for inverse in file.get_inverse(work_schedule): if inverse.is_a("IfcRelDefinesByObject"): - if inverse.RelatingObject == settings["work_schedule"] or len(inverse.RelatedObjects) == 1: + if inverse.RelatingObject == work_schedule or len(inverse.RelatedObjects) == 1: history = inverse.OwnerHistory file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) else: related_objects = list(inverse.RelatedObjects) - related_objects.remove(settings["work_schedule"]) + related_objects.remove(work_schedule) inverse.RelatedObjects = related_objects elif inverse.is_a("IfcRelAssignsToControl"): [ @@ -81,7 +79,7 @@ def remove_work_schedule(file: ifcopenshell.file, work_schedule: ifcopenshell.en if related_object.is_a("IfcTask") ] - history = settings["work_schedule"].OwnerHistory - file.remove(settings["work_schedule"]) + history = work_schedule.OwnerHistory + file.remove(work_schedule) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_process.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_process.py index 20e801a76c..1b2be09d20 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_process.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_process.py @@ -31,11 +31,8 @@ def unassign_process( See ifcopenshell.api.sequence.assign_process for details. :param relating_process: The IfcTask in the relationship. - :type relating_process: ifcopenshell.entity_instance :param related_object: The related object. - :type related_object: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -59,13 +56,8 @@ def unassign_process( # Change our mind. ifcopenshell.api.sequence.unassign_process(model, relating_process=task, related_object=wall) """ - settings = { - "relating_process": relating_process, - "related_object": related_object, - } - - for rel in settings["related_object"].HasAssignments or []: - if not rel.is_a("IfcRelAssignsToProcess") or rel.RelatingProcess != settings["relating_process"]: + for rel in related_object.HasAssignments or []: + if not rel.is_a("IfcRelAssignsToProcess") or rel.RelatingProcess != relating_process: continue if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory @@ -74,7 +66,7 @@ def unassign_process( ifcopenshell.util.element.remove_deep2(file, history) return related_objects = list(rel.RelatedObjects) - related_objects.remove(settings["related_object"]) + related_objects.remove(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, element=rel) return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_product.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_product.py index 30f2675aeb..ff59b463fa 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_product.py @@ -31,11 +31,8 @@ def unassign_product( See ifcopenshell.api.sequence.assign_product for details. :param relating_product: The IfcProduct in the relationship. - :type relating_product: ifcopenshell.entity_instance :param related_object: The IfcTask in the relationship. - :type related_object: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -59,13 +56,8 @@ def unassign_product( # Change our mind. ifcopenshell.api.sequence.unassign_product(relating_product=wall, related_object=task) """ - settings = { - "relating_product": relating_product, - "related_object": related_object, - } - - for rel in settings["related_object"].HasAssignments or []: - if not rel.is_a("IfcRelAssignsToProduct") or rel.RelatingProduct != settings["relating_product"]: + for rel in related_object.HasAssignments or []: + if not rel.is_a("IfcRelAssignsToProduct") or rel.RelatingProduct != relating_product: continue if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory @@ -74,7 +66,7 @@ def unassign_product( ifcopenshell.util.element.remove_deep2(file, history) return related_objects = list(rel.RelatedObjects) - related_objects.remove(settings["related_object"]) + related_objects.remove(related_object) rel.RelatedObjects = related_objects ifcopenshell.api.owner.update_owner_history(file, element=rel) return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_recurrence_pattern.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_recurrence_pattern.py index 2ba9cdb229..0c0dac45ee 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_recurrence_pattern.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_recurrence_pattern.py @@ -28,9 +28,7 @@ def unassign_recurrence_pattern(file: ifcopenshell.file, recurrence_pattern: ifc or replace IfcTaskTimeRecurring with IfcTaskTime). :param recurrence_pattern: The IfcRecurrencePattern to remove. - :type recurrence_pattern: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -50,8 +48,6 @@ def unassign_recurrence_pattern(file: ifcopenshell.file, recurrence_pattern: ifc # Change our mind, let's just maintain it whenever we feel like it. ifcopenshell.api.sequence.unassign_recurrence_pattern(recurrence_pattern=pattern) """ - settings = {"recurrence_pattern": recurrence_pattern} - - for time_period in settings["recurrence_pattern"].TimePeriods or []: + for time_period in recurrence_pattern.TimePeriods or []: file.remove(time_period) - file.remove(settings["recurrence_pattern"]) + file.remove(recurrence_pattern) diff --git a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_sequence.py b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_sequence.py index eea4e3eff5..15ed7d3cf1 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_sequence.py +++ b/src/ifcopenshell-python/ifcopenshell/api/sequence/unassign_sequence.py @@ -29,11 +29,8 @@ def unassign_sequence( """Removes a sequence relationship between tasks :param relating_process: The previous / predecessor task. - :type relating_process: ifcopenshell.entity_instance :param related_process: The next / successor task. - :type related_process: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -60,15 +57,10 @@ def unassign_sequence( ifcopenshell.api.sequence.unassign_sequence(model, relating_process=zone1, related_process=zone2) """ - settings = { - "relating_process": relating_process, - "related_process": related_process, - } - - for rel in settings["related_process"].IsSuccessorFrom or []: - if rel.RelatingProcess == settings["relating_process"]: + for rel in related_process.IsSuccessorFrom or []: + if rel.RelatingProcess == relating_process: history = rel.OwnerHistory file.remove(rel) if history: ifcopenshell.util.element.remove_deep2(file, history) - ifcopenshell.api.sequence.cascade_schedule(file, task=settings["related_process"]) + ifcopenshell.api.sequence.cascade_schedule(file, task=related_process) diff --git a/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py b/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py index 81dca88437..244b5ae8f7 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py +++ b/src/ifcopenshell-python/ifcopenshell/api/spatial/assign_container.py @@ -69,13 +69,11 @@ def assign_container( previous aggregation, containment, or nesting relationships it may have. :param products: A list of physical IfcElements existing in the space. - :type products: list[ifcopenshell.entity_instance] :param relating_structure: The IfcSpatialStructureElement element, such as IfcBuilding, IfcBuildingStorey, or IfcSpace that the element exists in. :return: The IfcRelContainedInSpatialStructure relationship instance or `None` if `products` was empty list. - :rtype: Union[ifcopenshell.entity_instance, None] Example: @@ -103,16 +101,10 @@ def assign_container( ifcopenshell.api.spatial.assign_container(model, products=[wall], relating_structure=storey) ifcopenshell.api.spatial.assign_container(model, products=[furniture], relating_structure=space) """ - settings = { - "products": products, - "relating_structure": relating_structure, - } - - if not settings["products"]: + if not products: return - products = set(settings["products"]) - relating_structure = settings["relating_structure"] + products_set = set(products) structure_rel = next(iter(relating_structure.ContainsElements), None) previous_containers_rels: set[ifcopenshell.entity_instance] = set() @@ -120,7 +112,7 @@ def assign_container( products_with_containers: list[ifcopenshell.entity_instance] = [] # check if there is anything to change - for product in products: + for product in products_set: product_rel = next(iter(product.ContainedInStructure), None) if product_rel is None: @@ -144,7 +136,7 @@ def assign_container( # unassign elements from previous containers for rel in previous_containers_rels: - related_elements = set(rel.RelatedElements) - products + related_elements = set(rel.RelatedElements) - products_set if related_elements: rel.RelatedElements = list(related_elements) ifcopenshell.api.owner.update_owner_history(file, **{"element": rel}) @@ -156,7 +148,7 @@ def assign_container( # assign elements to a new container if structure_rel: - structure_rel.RelatedElements = list(set(structure_rel.RelatedElements) | products) + structure_rel.RelatedElements = list(set(structure_rel.RelatedElements) | products_set) ifcopenshell.api.owner.update_owner_history(file, **{"element": structure_rel}) else: structure_rel = file.create_entity( @@ -164,8 +156,8 @@ def assign_container( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedElements": list(products), - "RelatingStructure": settings["relating_structure"], + "RelatedElements": list(products_set), + "RelatingStructure": relating_structure, } ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/spatial/unassign_container.py b/src/ifcopenshell-python/ifcopenshell/api/spatial/unassign_container.py index 9567fa4841..cd95dae448 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/spatial/unassign_container.py +++ b/src/ifcopenshell-python/ifcopenshell/api/spatial/unassign_container.py @@ -25,9 +25,7 @@ def unassign_container(file: ifcopenshell.file, products: list[ifcopenshell.enti """Unassigns a container from products. :param product: A list of IfcProducts to remove the containment from. - :type product: list[ifcopenshell.entity_instance] :return: None - :rtype: None Example: @@ -54,15 +52,11 @@ def unassign_container(file: ifcopenshell.file, products: list[ifcopenshell.enti # Not anymore! ifcopenshell.api.spatial.unassign_container(model, products=[wall]) """ - settings = { - "products": products, - } - - products = set(settings["products"]) - rels = set(rel for product in products if (rel := next(iter(product.ContainedInStructure), None))) + products_set = set(products) + rels = set(rel for product in products_set if (rel := next(iter(product.ContainedInStructure), None))) for rel in rels: - related_elements = set(rel.RelatedElements) - products + related_elements = set(rel.RelatedElements) - products_set if related_elements: rel.RelatedElements = list(related_elements) ifcopenshell.api.owner.update_owner_history(file, element=rel) diff --git a/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_activity.py b/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_activity.py index 53d07abcc6..466d26526f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_activity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_activity.py @@ -27,7 +27,7 @@ def add_structural_activity( ifc_class: str = "IfcStructuralPlanarAction", predefined_type: str = "CONST", global_or_local: Literal["GLOBAL_COORDS", "LOCAL_COORDS"] = "GLOBAL_COORDS", -) -> None: +) -> ifcopenshell.entity_instance: """Adds a new structural activity A structural activity is either a structural action or a reaction. It @@ -38,42 +38,29 @@ def add_structural_activity( a structural member. :param ifc_class: Choose from any subtype of IfcStructuralActivity. - :type ifc_class: str :param predefined_type: View the IFC documentation for what valid predefined types may be chosen. - :type predefined_type: str :param global_or_local: The location coordinates of the load is always defined locally relative to the structural member the activity is assigned to. However, the directions of the applied load may either be specified globally or locally depending on how this argument is set. Choose from GLOBAL_COORDS or LOCAL_COORDS. - :type global_or_local: str :param applied_load: The IfcStructuralLoad that is applied in this activity. - :type applied_load: ifcopenshell.entity_instance :param structural_member: The IfcStructuralMember that the load is applied to. - :type structural_member: ifcopenshell.entity_instance :return: The newly created entity based on the ifc_class - :rtype: ifcopenshell.entity_instance """ - settings = { - "ifc_class": ifc_class, - "predefined_type": predefined_type, - "global_or_local": global_or_local, - "applied_load": applied_load, - "structural_member": structural_member, - } activity = ifcopenshell.api.root.create_entity( file, - ifc_class=settings["ifc_class"], - predefined_type=settings["predefined_type"], + ifc_class=ifc_class, + predefined_type=predefined_type, ) - activity.AppliedLoad = settings["applied_load"] - activity.GlobalOrLocal = settings["global_or_local"] + activity.AppliedLoad = applied_load + activity.GlobalOrLocal = global_or_local rel = ifcopenshell.api.root.create_entity(file, ifc_class="IfcRelConnectsStructuralActivity") - rel.RelatingElement = settings["structural_member"] + rel.RelatingElement = structural_member rel.RelatedStructuralActivity = activity return activity diff --git a/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_boundary_condition.py b/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_boundary_condition.py index 36c232ecdd..4e3ac0c1b9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_boundary_condition.py +++ b/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_boundary_condition.py @@ -32,18 +32,14 @@ def add_structural_boundary_condition( edge condition, and surface connections will have a face condition. :param name: The name of the boundary condition. - :type name: str,optional :param connection: The IfcStructuralConnection to apply the boundary condition to. This will determine the type of condition that is created. If no connection is supplied, an orphan boundary condition will be created using the ifc_class that you specify. - :type connection: ifcopenshell.entity_instance,optional :param ifc_class: The class of IfcBoundaryCondition to create, only relevant if you do not specify a connection and want to create an orphaned boundary condition. - :type ifc_class: str,optional :return: The newly created IfcBoundaryCondition - :rtype: ifcopenshell.entity_instance Example: @@ -51,14 +47,12 @@ def add_structural_boundary_condition( ifcopenshell.api.structural.add_structural_boundary_condition(model, connection=connection) """ - settings = {"name": name, "connection": connection, "ifc_class": ifc_class} - - if settings["connection"]: + if connection: # assign boundary condition to a connection - if settings["connection"].is_a("IfcRelConnectsStructuralMember"): - related_connection = settings["connection"].RelatedStructuralConnection + if connection.is_a("IfcRelConnectsStructuralMember"): + related_connection = connection.RelatedStructuralConnection else: - related_connection = settings["connection"] + related_connection = connection if related_connection.is_a("IfcStructuralPointConnection"): boundary_class = "IfcBoundaryNodeCondition" @@ -67,9 +61,9 @@ def add_structural_boundary_condition( elif related_connection.is_a("IfcStructuralSurfaceConnection"): boundary_class = "IfcBoundaryFaceCondition" - condition = file.create_entity(boundary_class, Name=settings["name"]) - settings["connection"].AppliedCondition = condition + condition = file.create_entity(boundary_class, Name=name) + connection.AppliedCondition = condition return condition else: # add an orphan boundary condition - return file.create_entity(settings["ifc_class"], Name=settings["name"]) + return file.create_entity(ifc_class, Name=name) diff --git a/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_member_connection.py b/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_member_connection.py index 077e0a55fc..56ad73dca3 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_member_connection.py +++ b/src/ifcopenshell-python/ifcopenshell/api/structural/add_structural_member_connection.py @@ -29,22 +29,15 @@ def add_structural_member_connection( :param relating_structural_member: The IfcStructuralMember to have a connection added to it. - :type relating_structural_member: ifcopenshell.entity_instance :param related_structural_connection: The IfcStructuralConnection to add to the IfcStructuralMember. - :type related_structural_connection: ifcopenshell.entity_instance :return: The IfcRelConnectsStructuralMember relationship - :rtype: ifcopenshell.entity_instance """ - settings = { - "relating_structural_member": relating_structural_member, - "related_structural_connection": related_structural_connection, - } - for connection in settings["related_structural_connection"].ConnectsStructuralMembers or []: - if connection.RelatingStructuralMember == settings["relating_structural_member"]: + for connection in related_structural_connection.ConnectsStructuralMembers or []: + if connection.RelatingStructuralMember == relating_structural_member: return connection rel = ifcopenshell.api.root.create_entity(file, ifc_class="IfcRelConnectsStructuralMember") - rel.RelatingStructuralMember = settings["relating_structural_member"] - rel.RelatedStructuralConnection = settings["related_structural_connection"] + rel.RelatingStructuralMember = relating_structural_member + rel.RelatedStructuralConnection = related_structural_connection return rel diff --git a/src/ifcopenshell-python/ifcopenshell/api/structural/remove_structural_connection_condition.py b/src/ifcopenshell-python/ifcopenshell/api/structural/remove_structural_connection_condition.py index c16a441753..eea472ef73 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/structural/remove_structural_connection_condition.py +++ b/src/ifcopenshell-python/ifcopenshell/api/structural/remove_structural_connection_condition.py @@ -27,18 +27,14 @@ def remove_structural_connection_condition(file: ifcopenshell.file, relation: if The condition and the member itself is preserved. :param relation: The IfcRelConnectsStructuralMember to remove. - :type relation: ifcopenshell.entity_instance :return: None - :rtype: None """ - settings = {"relation": relation} - - if settings["relation"].AppliedCondition: + if relation.AppliedCondition: ifcopenshell.api.structural.remove_structural_boundary_condition( file, - connection=settings["relation"].RelatedStructuralConnection, + connection=relation.RelatedStructuralConnection, ) - history = settings["relation"].OwnerHistory - file.remove(settings["relation"]) + history = relation.OwnerHistory + file.remove(relation) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/style/remove_styled_representation.py b/src/ifcopenshell-python/ifcopenshell/api/style/remove_styled_representation.py index bc6267f0f7..d8441cd43a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/style/remove_styled_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/style/remove_styled_representation.py @@ -25,9 +25,7 @@ def remove_styled_representation(file: ifcopenshell.file, representation: ifcope removes the representation but not the underlying styles. :param representation: The IfcStyledRepresentation to remove. - :type representation: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -36,17 +34,15 @@ def remove_styled_representation(file: ifcopenshell.file, representation: ifcope # Remove a styled representation ifcopenshell.api.style.remove_styled_representation(model, representation=representation) """ - settings = {"representation": representation} - - for inverse in file.get_inverse(settings["representation"]): + for inverse in file.get_inverse(representation): if inverse.is_a("IfcMaterialDefinitionRepresentation") and len(inverse.Representations) == 1: file.remove(inverse) - for item in settings["representation"].Items: + for item in representation.Items: if item.is_a("IfcStyledItem") and file.get_total_inverses(item) == 1: for style in item.Styles: if style.is_a("IfcPresentationStyleAssignment"): file.remove(style) file.remove(item) - file.remove(settings["representation"]) + file.remove(representation) diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/add_port.py b/src/ifcopenshell-python/ifcopenshell/api/system/add_port.py index faa7c7a584..5c1ba67bda 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/add_port.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/add_port.py @@ -22,7 +22,9 @@ import ifcopenshell.api.system from typing import Optional -def add_port(file: ifcopenshell.file, element: Optional[ifcopenshell.entity_instance] = None) -> None: +def add_port( + file: ifcopenshell.file, element: Optional[ifcopenshell.entity_instance] = None +) -> ifcopenshell.entity_instance: """Adds a new distribution port to an element A distribution port represents a connection point on an element, where @@ -36,9 +38,7 @@ def add_port(file: ifcopenshell.file, element: Optional[ifcopenshell.entity_inst :param element: The IfcDistributionElement you want to add a distribution port to. - :type element: ifcopenshell.entity_instance, optional :return: The newly created IfcDistributionPort - :rtype: ifcopenshell.entity_instance Example: @@ -52,11 +52,7 @@ def add_port(file: ifcopenshell.file, element: Optional[ifcopenshell.entity_inst port1 = ifcopenshell.api.system.add_port(model, element=duct) port2 = ifcopenshell.api.system.add_port(model, element=duct) """ - settings = { - "element": element, - } - port = ifcopenshell.api.root.create_entity(file, ifc_class="IfcDistributionPort") - if settings["element"]: - ifcopenshell.api.system.assign_port(file, element=settings["element"], port=port) + if element: + ifcopenshell.api.system.assign_port(file, element=element, port=port) return port diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/add_system.py b/src/ifcopenshell-python/ifcopenshell/api/system/add_system.py index a9272ee989..dbd1f81e3c 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/add_system.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/add_system.py @@ -34,9 +34,7 @@ def add_system(file: ifcopenshell.file, ifc_class: str = "IfcDistributionSystem" security systems. Alternatively you may choose IfcBuildingSystem for specialised building facade systems or similar. For IFC2X3, choose IfcSystem. - :type ifc_class: str :return: The newly created IfcSystem. - :rtype: ifcopenshell.entity_instance Example: @@ -45,9 +43,7 @@ def add_system(file: ifcopenshell.file, ifc_class: str = "IfcDistributionSystem" # A completely empty distribution system system = ifcopenshell.api.system.add_system(model) """ - settings = {"ifc_class": ifc_class} - - ifc_class = settings["ifc_class"] + ifc_class = ifc_class # workaround for failing default argument in ifc2x3 if file.schema == "IFC2X3" and ifc_class == "IfcDistributionSystem": ifc_class = "IfcSystem" diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/assign_flow_control.py b/src/ifcopenshell-python/ifcopenshell/api/system/assign_flow_control.py index b41db08c79..011a510705 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/assign_flow_control.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/assign_flow_control.py @@ -34,12 +34,9 @@ def assign_flow_control( :param related_flow_control: IfcDistributionControlElement which may be used to impart control on the flow element - :type related_flow_control: ifcopenshell.entity_instance :param relating_flow_element: The IfcDistributionFlowElement that is being controlled / sensed - :type relating_flow_element: ifcopenshell.entity_instance :return: Matching or newly created IfcRelFlowControlElements. If control is already assigned to some other element method will return None. - :rtype: ifcopenshell.entity_instance, None Example: @@ -51,26 +48,21 @@ def assign_flow_control( model, related_flow_control=flow_control, relating_flow_element=flow_element ) """ - settings = { - "relating_flow_element": relating_flow_element, - "related_flow_control": related_flow_control, - } - - if settings["related_flow_control"].AssignedToFlowElement: + if related_flow_control.AssignedToFlowElement: # only 1 control per 1 flow element is possible - assignment = settings["related_flow_control"].AssignedToFlowElement[0] - if assignment.RelatingFlowElement == settings["relating_flow_element"]: + assignment = related_flow_control.AssignedToFlowElement[0] + if assignment.RelatingFlowElement == relating_flow_element: return assignment # return None if this control is already assigned to another flow element return - if settings["relating_flow_element"].HasControlElements: - assignment = settings["relating_flow_element"].HasControlElements[0] - if settings["related_flow_control"] in assignment.RelatedControlElements: + if relating_flow_element.HasControlElements: + assignment = relating_flow_element.HasControlElements[0] + if related_flow_control in assignment.RelatedControlElements: return assignment related_flow_controls = set(assignment.RelatedControlElements) - related_flow_controls.add(settings["related_flow_control"]) + related_flow_controls.add(related_flow_control) assignment.RelatedControlElements = list(related_flow_controls) ifcopenshell.api.owner.update_owner_history(file, **{"element": assignment}) return assignment @@ -80,8 +72,8 @@ def assign_flow_control( **{ "GlobalId": ifcopenshell.guid.new(), "OwnerHistory": ifcopenshell.api.owner.create_owner_history(file), - "RelatedControlElements": [settings["related_flow_control"]], - "RelatingFlowElement": settings["relating_flow_element"], + "RelatedControlElements": [related_flow_control], + "RelatingFlowElement": relating_flow_element, }, ) return assignment diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py b/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py index 8506e6b53d..75415fd98b 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/assign_port.py @@ -34,12 +34,9 @@ def assign_port( it may be useful when patching up models. :param element: The IfcDistributionElement to assign the port to. - :type element: ifcopenshell.entity_instance :param port: The IfcDistributionPort you want to assign. - :type port: ifcopenshell.entity_instance :return: The IfcRelNests relationship, or the IfcRelConnectsPortToElement for IFC2X3. - :rtype: ifcopenshell.entity_instance Example: @@ -61,31 +58,30 @@ def assign_port( """ usecase = Usecase() usecase.file = file - usecase.settings = { - "element": element, - "port": port, - } - return usecase.execute() + return usecase.execute(element, port) class Usecase: file: ifcopenshell.file - settings: dict[str, Any] - def execute(self): + def execute( + self, element: ifcopenshell.entity_instance, port: ifcopenshell.entity_instance + ) -> ifcopenshell.entity_instance: + self.element = element + self.port = port if self.file.schema == "IFC2X3": return self.execute_ifc2x3() - rels = self.settings["element"].IsNestedBy or [] + rels = self.element.IsNestedBy or [] for rel in rels: - if self.settings["port"] in rel.RelatedObjects: + if self.port in rel.RelatedObjects: return rel if rels: rel = rels[0] related_objects = set(rel.RelatedObjects) or set() - related_objects.add(self.settings["port"]) + related_objects.add(self.port) rel.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(self.file, **{"element": rel}) else: @@ -93,34 +89,34 @@ class Usecase: "IfcRelNests", GlobalId=ifcopenshell.guid.new(), OwnerHistory=ifcopenshell.api.owner.create_owner_history(self.file), - RelatedObjects=[self.settings["port"]], - RelatingObject=self.settings["element"], + RelatedObjects=[self.port], + RelatingObject=self.element, ) self.update_port_placement() return rel - def execute_ifc2x3(self): - for rel in self.settings["element"].HasPorts or []: - if rel.RelatingPort == self.settings["port"]: + def execute_ifc2x3(self) -> ifcopenshell.entity_instance: + for rel in self.element.HasPorts or []: + if rel.RelatingPort == self.port: return rel rel = self.file.create_entity( "IfcRelConnectsPortToElement", GlobalId=ifcopenshell.guid.new(), OwnerHistory=ifcopenshell.api.owner.create_owner_history(self.file), - RelatingPort=self.settings["port"], - RelatedElement=self.settings["element"], + RelatingPort=self.port, + RelatedElement=self.element, ) self.update_port_placement() return rel - def update_port_placement(self): - placement = getattr(self.settings["port"], "ObjectPlacement", None) + def update_port_placement(self) -> None: + placement = getattr(self.port, "ObjectPlacement", None) if placement and placement.is_a("IfcLocalPlacement"): ifcopenshell.api.geometry.edit_object_placement( self.file, - product=self.settings["port"], - matrix=ifcopenshell.util.placement.get_local_placement(self.settings["port"].ObjectPlacement), + product=self.port, + matrix=ifcopenshell.util.placement.get_local_placement(self.port.ObjectPlacement), is_si=False, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/disconnect_port.py b/src/ifcopenshell-python/ifcopenshell/api/system/disconnect_port.py index cd6cd38fb1..3bc1d6d2b5 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/disconnect_port.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/disconnect_port.py @@ -64,12 +64,8 @@ def disconnect_port(file: ifcopenshell.file, port: ifcopenshell.entity_instance) # fitting_port1 instead of duct_port2 ifcopenshell.api.system.disconnect_port(model, port=duct_port2) """ - settings = { - "port": port, - } - - rels = settings["port"].ConnectedTo or () - rels += settings["port"].ConnectedFrom or () + rels = port.ConnectedTo or () + rels += port.ConnectedFrom or () for rel in rels: rel.RelatingPort.FlowDirection = None diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/remove_system.py b/src/ifcopenshell-python/ifcopenshell/api/system/remove_system.py index cef253cded..6cd39cc298 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/remove_system.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/remove_system.py @@ -27,9 +27,7 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance) All the distribution elements within the system are retained. :param system: The IfcSystem to remove. - :type system: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -41,9 +39,7 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance) # Delete it. ifcopenshell.api.system.remove_system(model, system=system) """ - settings = {"system": system} - - for inverse_id in [i.id() for i in file.get_inverse(settings["system"])]: + for inverse_id in [i.id() for i in file.get_inverse(system)]: try: inverse = file.by_id(inverse_id) except: @@ -51,11 +47,11 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance) if inverse.is_a("IfcRelDefinesByProperties"): ifcopenshell.api.pset.remove_pset( file, - product=settings["system"], + product=system, pset=inverse.RelatingPropertyDefinition, ) elif inverse.is_a("IfcRelAssignsToGroup"): - if inverse.RelatingGroup == settings["system"]: + if inverse.RelatingGroup == system: history = inverse.OwnerHistory file.remove(inverse) if history: @@ -65,7 +61,7 @@ def remove_system(file: ifcopenshell.file, system: ifcopenshell.entity_instance) file.remove(inverse) if history: ifcopenshell.util.element.remove_deep2(file, history) - history = settings["system"].OwnerHistory - file.remove(settings["system"]) + history = system.OwnerHistory + file.remove(system) if history: ifcopenshell.util.element.remove_deep2(file, history) diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/unassign_flow_control.py b/src/ifcopenshell-python/ifcopenshell/api/system/unassign_flow_control.py index 4aeefe5a47..69b9ddfc62 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/unassign_flow_control.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/unassign_flow_control.py @@ -30,11 +30,8 @@ def unassign_flow_control( :param related_flow_control: IfcDistributionControlElement controling the flow element - :type related_flow_control: ifcopenshell.entity_instance :param relating_flow_element: The IfcDistributionFlowElement that is being controlled - :type relating_flow_element: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -53,15 +50,10 @@ def unassign_flow_control( ) """ - settings = { - "relating_flow_element": relating_flow_element, - "related_flow_control": related_flow_control, - } - - if not settings["related_flow_control"].AssignedToFlowElement: + if not related_flow_control.AssignedToFlowElement: return - assignment = settings["related_flow_control"].AssignedToFlowElement[0] - if assignment.RelatingFlowElement != settings["relating_flow_element"]: + assignment = related_flow_control.AssignedToFlowElement[0] + if assignment.RelatingFlowElement != relating_flow_element: return if len(assignment.RelatedControlElements) == 1: history = assignment.OwnerHistory @@ -70,6 +62,6 @@ def unassign_flow_control( ifcopenshell.util.element.remove_deep2(file, history) return related_flow_controls = list(assignment.RelatedControlElements) - related_flow_controls.remove(settings["related_flow_control"]) + related_flow_controls.remove(related_flow_control) assignment.RelatedControlElements = related_flow_controls ifcopenshell.api.owner.update_owner_history(file, **{"element": assignment}) diff --git a/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py b/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py index b5b69e276c..87b6c0fc16 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py +++ b/src/ifcopenshell-python/ifcopenshell/api/system/unassign_port.py @@ -19,7 +19,6 @@ import ifcopenshell import ifcopenshell.api.owner import ifcopenshell.util.element -from typing import Any def unassign_port( @@ -32,11 +31,8 @@ def unassign_port( port for cleaning or patchin purposes. :param element: The IfcDistributionElement to unassign the port from. - :type element: ifcopenshell.entity_instance :param port: The IfcDistributionPort you want to unassign. - :type port: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -55,23 +51,20 @@ def unassign_port( """ usecase = Usecase() usecase.file = file - usecase.settings = { - "element": element, - "port": port, - } - return usecase.execute() + return usecase.execute(element, port) class Usecase: file: ifcopenshell.file - settings: dict[str, Any] - def execute(self): + def execute(self, element: ifcopenshell.entity_instance, port: ifcopenshell.entity_instance) -> None: if self.file.schema == "IFC2X3": + self.element = element + self.port = port return self.execute_ifc2x3() - for rel in self.settings["element"].IsNestedBy or []: - if self.settings["port"] in rel.RelatedObjects: + for rel in element.IsNestedBy or []: + if port in rel.RelatedObjects: if len(rel.RelatedObjects) == 1: history = rel.OwnerHistory self.file.remove(rel) @@ -79,13 +72,13 @@ class Usecase: ifcopenshell.util.element.remove_deep2(self.file, history) return related_objects = set(rel.RelatedObjects) or set() - related_objects.remove(self.settings["port"]) + related_objects.remove(port) rel.RelatedObjects = list(related_objects) ifcopenshell.api.owner.update_owner_history(self.file, **{"element": rel}) - def execute_ifc2x3(self): - for rel in self.settings["element"].HasPorts or []: - if rel.RelatingPort == self.settings["port"]: + def execute_ifc2x3(self) -> None: + for rel in self.element.HasPorts or []: + if rel.RelatingPort == self.port: history = rel.OwnerHistory self.file.remove(rel) if history: diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py b/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py index 995408b063..0c4c66ae16 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/map_type_representations.py @@ -33,11 +33,8 @@ def map_type_representations( be used to ensure consistency of the occurrence's representations. :param related_object: The IfcElement occurrence. - :type related_object: ifcopenshell.entity_instance :param relating_type: The IfcElementType type. - :type relating_type: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -84,28 +81,23 @@ def map_type_representations( # ifcopenshell.api.type.map_type_representations(model, # related_object=furniture, relating_type=furniture_type) """ - settings = { - "related_object": related_object, - "relating_type": relating_type, - } - - if not settings["relating_type"].RepresentationMaps: + if not relating_type.RepresentationMaps: return representations = [] - if settings["related_object"].Representation: - representations = settings["related_object"].Representation.Representations + if related_object.Representation: + representations = related_object.Representation.Representations for representation in representations: ifcopenshell.api.geometry.unassign_representation( file, - product=settings["related_object"], + product=related_object, representation=representation, ) - ifcopenshell.api.geometry.remove_representation(file, **{"representation": representation}) - for representation_map in settings["relating_type"].RepresentationMaps: + ifcopenshell.api.geometry.remove_representation(file, representation=representation) + for representation_map in relating_type.RepresentationMaps: representation = representation_map.MappedRepresentation mapped_representation = ifcopenshell.api.geometry.map_representation(file, representation=representation) ifcopenshell.api.geometry.assign_representation( file, - product=settings["related_object"], + product=related_object, representation=mapped_representation, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py index 135c805f2f..f9c76f9072 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py @@ -35,9 +35,7 @@ def add_context_dependent_unit( sensible normal unit for. In that case, firstly stop whatever you're doing and have a hard think about your life, and then if life really is going that badly for you, check out the IFC docs for IfcUnitEnum. - :type unit_type: str :param name: Give your unit a name. X what? X bananas? - :type name: str :param dimensions: Units typically measure one of 7 fundamental physical dimensions: length, mass, time, electric current, temperature, substance amount, or luminous intensity. These are represented as a @@ -46,9 +44,7 @@ def add_context_dependent_unit( where as an area unit is (2, 0, 0, 0, 0, 0, 0). A unit of meters per second is (1, 0, -1, 0, 0, 0, 0). For context dependent units, it is recommended to leave this as the default of (0, 0, 0, 0, 0, 0, 0). - :type dimensions: list[int] :return: The new IfcContextDependentUnit - :rtype: ifcopenshell.entity_instance Example: @@ -57,11 +53,9 @@ def add_context_dependent_unit( # Boxes of things ifcopenshell.api.unit.add_context_dependent_unit(model, name="BOXES") """ - settings = {"unit_type": unit_type, "name": name, "dimensions": dimensions} - return file.create_entity( "IfcContextDependentUnit", - Dimensions=file.createIfcDimensionalExponents(*settings["dimensions"]), - UnitType=settings["unit_type"], - Name=settings["name"], + Dimensions=file.createIfcDimensionalExponents(*dimensions), + UnitType=unit_type, + Name=name, ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py index daa91145ee..bb1e920257 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py @@ -36,17 +36,14 @@ def add_conversion_based_unit( kip, psi, ksi, minute, hour, day, btu, and fahrenheit. :param name: A converted name chosen from the list above. - :type name: str :param conversion_offset: If you want to offset the conversion further by a set number, you may specify it here. For example, fahrenheit is 1.8 * kelvin - 459.67. The -459.67 is the conversion offset. Note that this is just an example and you don't actually need to specify that for fahrenheit as it's built into this API function. For advanced users only. - :type conversion_offset: float, optional :return: The new IfcConversionBasedUnit or IfcConversionBasedUnitWithOffset - :rtype: ifcopenshell.entity_instance Example: @@ -59,28 +56,26 @@ def add_conversion_based_unit( # Make it our default units, if we are doing an imperial building ifcopenshell.api.unit.assign_unit(model, units=[length, area]) """ - settings = {"name": name, "conversion_offset": conversion_offset} - unit_type = ifcopenshell.util.unit.imperial_types.get(settings["name"], "USERDEFINED") + unit_type = ifcopenshell.util.unit.imperial_types.get(name, "USERDEFINED") dimensions = ifcopenshell.util.unit.named_dimensions[unit_type] exponents = file.createIfcDimensionalExponents(*dimensions) si_name = ifcopenshell.util.unit.si_type_names[unit_type] si_unit = file.createIfcSIUnit(UnitType=unit_type, Name=si_name) - conversion_real = ifcopenshell.util.unit.si_conversions.get(settings["name"], 1) + conversion_real = ifcopenshell.util.unit.si_conversions.get(name, 1) value_component = file.create_entity("IfcReal", **{"wrappedValue": conversion_real}) conversion_factor = file.createIfcMeasureWithUnit(value_component, si_unit) - conversion_offset = settings["conversion_offset"] if not conversion_offset: - conversion_offset = ifcopenshell.util.unit.si_offsets.get(settings["name"], 0) + conversion_offset = ifcopenshell.util.unit.si_offsets.get(name, 0) if conversion_offset: return file.createIfcConversionBasedUnitWithOffset( exponents, unit_type, - settings["name"], + name, conversion_factor, conversion_offset, ) - return file.createIfcConversionBasedUnit(exponents, unit_type, settings["name"], conversion_factor) + return file.createIfcConversionBasedUnit(exponents, unit_type, name, conversion_factor) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py index 8d4a3130f0..6c5a90e12d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py @@ -26,9 +26,7 @@ def add_monetary_unit(file: ifcopenshell.file, currency: str = "DOLLARYDOO") -> USD, GBP, AUD, MYR, etc. :param currency: The currency code - :type currency: str :return: The newly created IfcMonetaryUnit - :rtype: ifcopenshell.entity_instance Example: @@ -41,6 +39,4 @@ def add_monetary_unit(file: ifcopenshell.file, currency: str = "DOLLARYDOO") -> # Make it our default currency ifcopenshell.api.unit.assign_unit(model, units=[zwl]) """ - settings = {"currency": currency} - - return file.create_entity("IfcMonetaryUnit", settings["currency"]) + return file.create_entity("IfcMonetaryUnit", currency) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py index 56cab159ab..50da1c10f2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py @@ -40,12 +40,9 @@ def add_si_unit( :param unit_type: A type of unit chosen from the list above. For example, choosing LENGTHUNIT will give you a metre. - :type unit_type: str :param prefix: A prefix chosen from the list above, or None for no prefix. - :type prefix: str,optional :return: The newly created IfcSIUnit - :rtype: ifcopenshell.entity_instance Example: @@ -58,7 +55,5 @@ def add_si_unit( # Make it our default units, if we are doing a metric building ifcopenshell.api.unit.assign_unit(model, units=[length, area]) """ - settings = {"unit_type": unit_type, "prefix": prefix} - - name = ifcopenshell.util.unit.si_type_names.get(settings["unit_type"], None) - return file.create_entity("IfcSIUnit", UnitType=settings["unit_type"], Name=name, Prefix=settings["prefix"]) + name = ifcopenshell.util.unit.si_type_names.get(unit_type, None) + return file.create_entity("IfcSIUnit", UnitType=unit_type, Name=name, Prefix=prefix) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py index 88cffbc4a0..a9920e0e5c 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py @@ -27,9 +27,7 @@ def remove_unit(file: ifcopenshell.file, unit: ifcopenshell.entity_instance) -> defined quantities in the model completely lose their meaning. :param unit: The unit element to remove - :type unit: ifcopenshell.entity_instance :return: None - :rtype: None Example: @@ -41,14 +39,12 @@ def remove_unit(file: ifcopenshell.file, unit: ifcopenshell.entity_instance) -> # Yeah maybe not. ifcopenshell.api.unit.remove_unit(model, unit=unit) """ - settings = {"unit": unit} - unit_assignment = ifcopenshell.util.unit.get_unit_assignment(file) - if unit_assignment and settings["unit"] in unit_assignment.Units: + if unit_assignment and unit in unit_assignment.Units: units = list(unit_assignment.Units) - units.remove(settings["unit"]) + units.remove(unit) if units: unit_assignment.Units = units else: file.remove(unit_assignment) - ifcopenshell.util.element.remove_deep(file, settings["unit"]) + ifcopenshell.util.element.remove_deep(file, unit) diff --git a/src/ifcopenshell-python/ifcopenshell/util/cost.py b/src/ifcopenshell-python/ifcopenshell/util/cost.py index b63976a4ed..5d9189b337 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/cost.py +++ b/src/ifcopenshell-python/ifcopenshell/util/cost.py @@ -280,7 +280,7 @@ def get_cost_values(cost_item: ifcopenshell.entity_instance) -> list[dict[str, s return results -def get_cost_schedule_types(file): +def get_cost_schedule_types(file: ifcopenshell.file) -> list[dict[str, str]]: schema: ifcopenshell_wrapper.schema_definition = ifcopenshell_wrapper.schema_by_name(file.schema) results = [] declaration = schema.declaration_by_name("IfcCostSchedule")