From 88befea1746a126399b7b3796e19966c453a0c77 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 22 May 2025 11:42:56 +0500 Subject: [PATCH] typing --- .../bonsai/bim/module/clash/operator.py | 2 +- src/bonsai/bonsai/bim/module/clash/ui.py | 3 +++ src/bonsai/bonsai/tool/clash.py | 10 +++----- src/ifcclash/ifcclash/ifcclash.py | 23 +++++++++++++++---- .../ifcopenshell/geom/main.py | 8 +++---- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/clash/operator.py b/src/bonsai/bonsai/bim/module/clash/operator.py index e6229bbff9..4509c0083a 100644 --- a/src/bonsai/bonsai/bim/module/clash/operator.py +++ b/src/bonsai/bonsai/bim/module/clash/operator.py @@ -425,7 +425,7 @@ class SelectClash(bpy.types.Operator): if not clash: return {"FINISHED"} - products = [] + products: list[ifcopenshell.entity_instance] = [] for global_id in (clash["a_global_id"], clash["b_global_id"]): try: diff --git a/src/bonsai/bonsai/bim/module/clash/ui.py b/src/bonsai/bonsai/bim/module/clash/ui.py index f1071e7010..93cc1c45e0 100644 --- a/src/bonsai/bonsai/bim/module/clash/ui.py +++ b/src/bonsai/bonsai/bim/module/clash/ui.py @@ -23,6 +23,7 @@ import bonsai.bim.helper from bpy.types import Panel from bonsai.bim.module.clash.data import ClashData from typing import TYPE_CHECKING +from typing_extensions import assert_never if TYPE_CHECKING: from bonsai.bim.module.clash.prop import BIMClashProperties, ClashSet, SmartClashGroup, Clash @@ -80,6 +81,8 @@ class BIM_PT_ifcclash(Panel): row.prop(clash_set, "clearance") row = layout.row() row.prop(clash_set, "check_all") + else: + assert_never(clash_set.mode) def draw_clash_set_group(group: tool.Clash.ClashSourceGroup) -> None: row = layout.row(align=True) diff --git a/src/bonsai/bonsai/tool/clash.py b/src/bonsai/bonsai/tool/clash.py index f99203db2d..7948e929de 100644 --- a/src/bonsai/bonsai/tool/clash.py +++ b/src/bonsai/bonsai/tool/clash.py @@ -132,14 +132,10 @@ class Clash(bonsai.core.tool.Clash): @classmethod def look_at(cls, target: Vector, location: Vector) -> None: camera_location = location - area = tool.Blender.get_view3d_area() - region = next(region for region in area.regions if region.type == "WINDOW") - space = next(space for space in area.spaces if space.type == "VIEW_3D") - override = {"area": area, "region": region, "space_data": space} - assert isinstance(space, bpy.types.SpaceView3D) - assert space.region_3d + space = tool.Blender.get_view3d_space() + assert space and space.region_3d space.region_3d.view_location = target - space.region_3d.view_rotation = Vector((camera_location - target)).to_track_quat("Z", "Y") + space.region_3d.view_rotation = (camera_location - target).to_track_quat("Z", "Y") space.region_3d.view_distance = (camera_location - target).length space.shading.show_xray = True diff --git a/src/ifcclash/ifcclash/ifcclash.py b/src/ifcclash/ifcclash/ifcclash.py index 04605a2806..201c2518d6 100644 --- a/src/ifcclash/ifcclash/ifcclash.py +++ b/src/ifcclash/ifcclash/ifcclash.py @@ -29,7 +29,7 @@ import ifcopenshell.geom import ifcopenshell.util.selector from logging import Logger from typing import Literal, TypedDict, Union -from typing_extensions import NotRequired +from typing_extensions import NotRequired, assert_never class ClashSource(TypedDict): @@ -61,7 +61,7 @@ class ClashSet(TypedDict): a: list[ClashSource] b: NotRequired[list[ClashSource]] mode: Literal["intersection", "collision", "clearance"] - # Added during clash. + # Clash results, added during clash. clashes: NotRequired[dict[str, ClashResult]] # intersection, clearance modes. check_all: NotRequired[bool] @@ -74,7 +74,7 @@ class ClashSet(TypedDict): class ClashGroup(TypedDict): - elements: dict + elements: dict[str, ifcopenshell.entity_instance] objects: dict @@ -110,6 +110,7 @@ class Clasher: mode = clash_set["mode"] if mode == "intersection": + assert "tolerance" in clash_set and "check_all" in clash_set results = self.tree.clash_intersection_many( list(self.groups["a"]["elements"].values()), list(self.groups[b]["elements"].values()), @@ -117,12 +118,14 @@ class Clasher: check_all=clash_set["check_all"], ) elif mode == "collision": + assert "allow_touching" in clash_set results = self.tree.clash_collision_many( list(self.groups["a"]["elements"].values()), list(self.groups[b]["elements"].values()), allow_touching=clash_set["allow_touching"], ) elif mode == "clearance": + assert "clearance" in clash_set and "check_all" in clash_set results = self.tree.clash_clearance_many( list(self.groups["a"]["elements"].values()), list(self.groups[b]["elements"].values()), @@ -130,7 +133,7 @@ class Clasher: check_all=clash_set["check_all"], ) else: - assert False, f"Unexpected mode '{mode}'." + assert_never(mode) processed_results: dict[str, ClashResult] = {} for result in results: @@ -144,7 +147,7 @@ class Clasher: b_ifc_class=element2.is_a(), a_name=element1.get_argument(2), b_name=element2.get_argument(2), - type=["protrusion", "pierce", "collision", "clearance"][result.clash_type], + type=("protrusion", "pierce", "collision", "clearance")[result.clash_type], p1=list(result.p1), p2=list(result.p2), distance=result.distance, @@ -173,10 +176,14 @@ class Clasher: ifc_file: ifcopenshell.file, source: ClashSource, ) -> None: + """Process filters, add tree and group elements.""" + assert self.tree mode = source.get("mode") selector = source.get("selector") start = time.time() self.settings.logger.info("Creating iterator") + + # Process filters. if not mode or mode == "a" or not selector: elements = set(ifc_file.by_type("IfcElement")) elements -= set(ifc_file.by_type("IfcFeatureElement")) @@ -186,11 +193,15 @@ class Clasher: elements -= set(ifcopenshell.util.selector.filter_elements(ifc_file, selector)) elif mode == "i": elements = set(ifcopenshell.util.selector.filter_elements(ifc_file, selector)) + else: + assert_never(mode) + iterator = ifcopenshell.geom.iterator( self.geom_settings, ifc_file, multiprocessing.cpu_count(), include=elements ) self.settings.logger.info(f"Iterator creation finished {time.time() - start}") + # Add tree elements. start = time.time() self.logger.info(f"Adding objects {name} ({len(elements)} elements)") assert iterator.initialize() @@ -200,6 +211,8 @@ class Clasher: if not iterator.next(): break self.logger.info(f"Tree finished {time.time() - start}") + + # Add group elements. start = time.time() self.groups[name]["elements"].update({e.GlobalId: e for e in elements}) self.logger.info(f"Element metadata finished {time.time() - start}") diff --git a/src/ifcopenshell-python/ifcopenshell/geom/main.py b/src/ifcopenshell-python/ifcopenshell/geom/main.py index fa0db6a2c7..e467ae5bc0 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/main.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/main.py @@ -28,7 +28,7 @@ from ..entity_instance import entity_instance from . import has_occ -from typing import TypeVar, Union, Optional, Generator, Any, Literal, overload, TYPE_CHECKING, Iterable, cast +from typing import TypeVar, Union, Optional, Generator, Any, Literal, overload, TYPE_CHECKING, Iterable, cast, TypedDict if TYPE_CHECKING: from OCC.Core import TopoDS @@ -409,13 +409,13 @@ class tree(ifcopenshell_wrapper.tree): set_b: Iterable[entity_instance], tolerance: float = 0.002, check_all: bool = True, - ): + ) -> tuple[ifcopenshell_wrapper.clash, ...]: args = [self, [e.wrapped_data for e in set_a], [e.wrapped_data for e in set_b], tolerance, check_all] return ifcopenshell_wrapper.tree.clash_intersection_many(*args) def clash_collision_many( self, set_a: Iterable[entity_instance], set_b: Iterable[entity_instance], allow_touching=False - ): + ) -> tuple[ifcopenshell_wrapper.clash, ...]: args = [self, [e.wrapped_data for e in set_a], [e.wrapped_data for e in set_b], allow_touching] return ifcopenshell_wrapper.tree.clash_collision_many(*args) @@ -425,7 +425,7 @@ class tree(ifcopenshell_wrapper.tree): set_b: Iterable[entity_instance], clearance: float = 0.05, check_all: bool = False, - ): + ) -> tuple[ifcopenshell_wrapper.clash, ...]: args = [self, [e.wrapped_data for e in set_a], [e.wrapped_data for e in set_b], clearance, check_all] return ifcopenshell_wrapper.tree.clash_clearance_many(*args)