From ecf461e1e0af3b770fc9bce61ce9da10349ad855 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 29 Apr 2025 15:05:25 +0500 Subject: [PATCH] typing --- src/bonsai/bonsai/bim/import_ifc.py | 20 +++++++++++++----- .../bonsai/bim/module/drawing/operator.py | 8 ++++--- src/bonsai/bonsai/bim/module/model/array.py | 15 ++++++------- src/bonsai/bonsai/bim/module/model/grid.py | 21 ++++++++++++------- src/bonsai/bonsai/tool/model.py | 1 + .../api/grid/create_axis_curve.py | 8 +++---- .../ifcopenshell/api/grid/create_grid_axis.py | 5 ----- 7 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index d4de537955..cb883086ac 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -198,11 +198,16 @@ class MaterialCreator: class IfcImporter: + file: ifcopenshell.file + """Either provided by user as an attribute or will be loaded from ``input_file`` during ``execute()``.""" + + elements: set[ifcopenshell.entity_instance] + """Set of IfcElements to import. Excluding ``gross_elements`` and ```native_elements``.""" + def __init__(self, ifc_import_settings: IfcImportSettings): self.ifc_import_settings = ifc_import_settings tool.Loader.set_settings(ifc_import_settings) self.diff = None - self.file: ifcopenshell.file = None self.project = None self.has_existing_project = False # element guids to blender collections mapping @@ -300,6 +305,7 @@ class IfcImporter: bpy.context.window_manager.progress_end() def process_context_filter(self) -> None: + """Setup contexts. Necessary for importing elements representations.""" contexts = self.file.by_type("IfcGeometricRepresentationContext") if len(contexts) > 100: # Probably something strange happening. Encountered from Revizto. print("Warning! Excessive contexts were found and merged where applicable.") @@ -384,6 +390,7 @@ class IfcImporter: return results def parse_native_elements(self) -> None: + # TODO: move to `process_element_filter` to incapsulate all `self.elements` logic. if not self.ifc_import_settings.should_load_geometry: return if not self.file.by_type("IfcSweptDiskSolid"): @@ -1129,7 +1136,7 @@ class IfcImporter: bpy.ops.view3d.view_selected() bpy.ops.object.select_all(action="DESELECT") - def setup_arrays(self): + def setup_arrays(self, elements: Optional[set[ifcopenshell.entity_instance]] = None): for pset in self.file.by_type("IfcPropertySet"): if pset.Name != "BBIM_Array": continue @@ -1144,9 +1151,10 @@ class IfcImporter: class IfcImportSettings: + input_file: Union[str, None] = None + logger: Union[logging.Logger, None] = None + def __init__(self): - self.logger: logging.Logger = None - self.input_file = None self.diff_file = None self.geometry_library = "opencascade" self.should_use_cpu_multiprocessing = True @@ -1177,7 +1185,9 @@ class IfcImportSettings: self.load_indexed_maps = False @staticmethod - def factory(context=None, input_file=None, logger=None): + def factory( + context=None, input_file: Optional[str] = None, logger: Optional[logging.Logger] = None + ) -> IfcImportSettings: scene_diff = tool.Blender.get_diff_props() props = tool.Project.get_project_props() settings = IfcImportSettings() diff --git a/src/bonsai/bonsai/bim/module/drawing/operator.py b/src/bonsai/bonsai/bim/module/drawing/operator.py index e32ad03a4d..59743e5af9 100644 --- a/src/bonsai/bonsai/bim/module/drawing/operator.py +++ b/src/bonsai/bonsai/bim/module/drawing/operator.py @@ -58,6 +58,7 @@ from bpy_extras.image_utils import load_image if TYPE_CHECKING: from bonsai.bim.module.project.prop import Link + from bpy._typing import rna_enums cwd = os.path.dirname(os.path.realpath(__file__)) @@ -223,6 +224,7 @@ class CreateDrawing(bpy.types.Operator): ) drawing_name: str + is_manifold_cache: dict[str, bool] @classmethod def poll(cls, context): @@ -1225,7 +1227,7 @@ class CreateDrawing(bpy.types.Operator): ) return classes - def is_manifold(self, obj): + def is_manifold(self, obj) -> bool: result = self.is_manifold_cache.get(obj.data.name, None) if result is not None: return result @@ -2127,14 +2129,14 @@ class ActivateModel(bpy.types.Operator): class ActivateDrawingBase: - def invoke(self, context, event): + def invoke(self, context, event) -> set["rna_enums.OperatorReturnItems"]: if event.type == "LEFTMOUSE" and event.alt: self.should_view_from_camera = False if event.type == "LEFTMOUSE" and event.shift: self.use_quick_preview = True return self.execute(context) - def execute(self, context): + def execute(self, context) -> set["rna_enums.OperatorReturnItems"]: props = tool.Drawing.get_document_props() if props.is_editing_drawings == False: bpy.ops.bim.load_drawings() diff --git a/src/bonsai/bonsai/bim/module/model/array.py b/src/bonsai/bonsai/bim/module/model/array.py index 0ec49d5561..fd023b94da 100644 --- a/src/bonsai/bonsai/bim/module/model/array.py +++ b/src/bonsai/bonsai/bim/module/model/array.py @@ -20,6 +20,7 @@ import bpy import json import ifcopenshell import ifcopenshell.api +import ifcopenshell.api.pset import ifcopenshell.util.element import ifcopenshell.util.unit import bonsai.tool as tool @@ -33,8 +34,9 @@ class AddArray(bpy.types.Operator, tool.Ifc.Operator): bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - obj = context.active_object - element = tool.Ifc.get_entity(obj) + assert (obj := context.active_object) + assert (element := tool.Ifc.get_entity(obj)) + ifc_file = tool.Ifc.get() array = { "children": [], @@ -54,14 +56,13 @@ class AddArray(bpy.types.Operator, tool.Ifc.Operator): data.append(array) pset = tool.Ifc.get().by_id(pset["id"]) else: - pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Array") + pset = ifcopenshell.api.pset.add_pset(ifc_file, product=element, name="BBIM_Array") data = [array] - ifcopenshell.api.run( - "pset.edit_pset", - tool.Ifc.get(), + ifcopenshell.api.pset.edit_pset( + ifc_file, pset=pset, - properties={"Parent": element.GlobalId, "Data": tool.Ifc.get().createIfcText(json.dumps(data))}, + properties={"Parent": element.GlobalId, "Data": ifc_file.create_entity("IfcText", json.dumps(data))}, ) return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/model/grid.py b/src/bonsai/bonsai/bim/module/model/grid.py index 0411f2875d..ae1eb3c9f2 100644 --- a/src/bonsai/bonsai/bim/module/model/grid.py +++ b/src/bonsai/bonsai/bim/module/model/grid.py @@ -18,14 +18,17 @@ import bpy import ifcopenshell.api +import ifcopenshell.api.grid import bonsai.tool as tool import bonsai.core.root from bpy.types import Operator from bpy.props import FloatProperty, IntProperty from mathutils import Vector +from typing import TYPE_CHECKING -def add_object(self, context): +def add_object(self: "BIM_OT_add_object", context: bpy.types.Context) -> None: + ifc_file = tool.Ifc.get() obj = bpy.data.objects.new("Grid", None) obj.name = "Grid" @@ -33,6 +36,7 @@ def add_object(self, context): tool.Ifc, tool.Collector, tool.Root, obj=obj, ifc_class="IfcGrid", should_add_representation=False ) grid = tool.Ifc.get_entity(obj) + assert grid for i in range(0, self.total_u): verts = [ @@ -46,9 +50,7 @@ def add_object(self, context): tag = chr(ord("A") + i) obj = bpy.data.objects.new(f"IfcGridAxis/{tag}", mesh) - result = ifcopenshell.api.run( - "grid.create_grid_axis", tool.Ifc.get(), axis_tag=tag, uvw_axes="UAxes", grid=grid - ) + result = ifcopenshell.api.grid.create_grid_axis(ifc_file, axis_tag=tag, uvw_axes="UAxes", grid=grid) tool.Ifc.link(result, obj) tool.Model.create_axis_curve(obj, result) tool.Collector.assign(obj) @@ -65,9 +67,7 @@ def add_object(self, context): tag = str(i + 1).zfill(2) obj = bpy.data.objects.new(f"IfcGridAxis/{tag}", mesh) - result = ifcopenshell.api.run( - "grid.create_grid_axis", tool.Ifc.get(), axis_tag=tag, uvw_axes="VAxes", grid=grid - ) + result = ifcopenshell.api.grid.create_grid_axis(ifc_file, axis_tag=tag, uvw_axes="VAxes", grid=grid) tool.Ifc.link(result, obj) tool.Model.create_axis_curve(obj, result) tool.Collector.assign(obj) @@ -78,6 +78,7 @@ def add_object(self, context): class BIM_OT_add_object(Operator, tool.Ifc.Operator): bl_idname = "mesh.add_grid" bl_label = "Grid" + bl_description = "Add IfcGrid." bl_options = {"REGISTER", "UNDO"} u_spacing: FloatProperty(name="U Spacing", default=10) @@ -85,6 +86,12 @@ class BIM_OT_add_object(Operator, tool.Ifc.Operator): v_spacing: FloatProperty(name="V Spacing", default=10) total_v: IntProperty(name="Number of V Grids", default=3) + if TYPE_CHECKING: + u_spacing: float + total_u: int + v_spacing: float + total_v: int + @classmethod def poll(cls, context): return tool.Ifc.get() and context.mode == "OBJECT" diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index e179de44e7..c55b2c6b37 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -2123,6 +2123,7 @@ class Model(bonsai.core.tool.Model): @classmethod def create_axis_curve(cls, obj: bpy.types.Object, grid_axis: ifcopenshell.entity_instance) -> None: m = tool.Surveyor.get_absolute_matrix(obj) + assert isinstance(obj.data, bpy.types.Mesh) points = [m @ np.array(v.co.to_4d()) for v in obj.data.vertices[0:2]] ifcopenshell.api.grid.create_axis_curve( tool.Ifc.get(), p1=points[0], p2=points[1], is_si=True, grid_axis=grid_axis diff --git a/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py b/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py index 4e692008e3..5bbfa5a8ea 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py +++ b/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py @@ -69,10 +69,10 @@ def create_axis_curve( grid = [i for i in file.get_inverse(grid_axis) if i.is_a("IfcGrid")][0] grid_matrix_i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(grid.ObjectPlacement)) - grid_axis.AxisCurve = file.createIfcPolyline( - ( - file.createIfcCartesianPoint(ifc_safe_vector_type(grid_matrix_i @ p1)), - file.createIfcCartesianPoint(ifc_safe_vector_type(grid_matrix_i @ p2)), + grid_axis.AxisCurve = file.create_entity( + "IfcPolyline"( + file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(grid_matrix_i @ p1)), + file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(grid_matrix_i @ p2)), ) ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/grid/create_grid_axis.py b/src/ifcopenshell-python/ifcopenshell/api/grid/create_grid_axis.py index ecd286dd44..77228434b0 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/grid/create_grid_axis.py +++ b/src/ifcopenshell-python/ifcopenshell/api/grid/create_grid_axis.py @@ -50,20 +50,15 @@ def create_grid_axis( :param axis_tag: The name of the axis, that would typically be labeled on drawings or described on site during coordination, such as A, B, C, 1, 2, 3, etc. Defaults to "A". - :type axis_tag: str, optional :param same_sense: Determines whether the direction of the axis's line is reversed. True means the direction the geometry is defined in represents the direction of the axis. False means the direction is reversed. Leave as True if unsure. Defaults to "True". - :type same_sense: bool, optional :param uvw_axes: Choose from "UAxes", "VAxes" or "WAxes" depending on which set of axes the new axis you are adding should belong to. Defaults to "UAxes". - :type uvw_axes: str, optional :param grid: The IfcGrid you are adding the axis to. - :type grid: ifcopenshell.entity_instance :return: The newly created IfcGridAxis - :rtype: ifcopenshell.entity_instance Example: