This commit is contained in:
Andrej730
2025-05-22 11:42:56 +05:00
parent 441e2ddbd6
commit 88befea174
5 changed files with 29 additions and 17 deletions
@@ -425,7 +425,7 @@ class SelectClash(bpy.types.Operator):
if not clash: if not clash:
return {"FINISHED"} return {"FINISHED"}
products = [] products: list[ifcopenshell.entity_instance] = []
for global_id in (clash["a_global_id"], clash["b_global_id"]): for global_id in (clash["a_global_id"], clash["b_global_id"]):
try: try:
+3
View File
@@ -23,6 +23,7 @@ import bonsai.bim.helper
from bpy.types import Panel from bpy.types import Panel
from bonsai.bim.module.clash.data import ClashData from bonsai.bim.module.clash.data import ClashData
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing_extensions import assert_never
if TYPE_CHECKING: if TYPE_CHECKING:
from bonsai.bim.module.clash.prop import BIMClashProperties, ClashSet, SmartClashGroup, Clash 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.prop(clash_set, "clearance")
row = layout.row() row = layout.row()
row.prop(clash_set, "check_all") row.prop(clash_set, "check_all")
else:
assert_never(clash_set.mode)
def draw_clash_set_group(group: tool.Clash.ClashSourceGroup) -> None: def draw_clash_set_group(group: tool.Clash.ClashSourceGroup) -> None:
row = layout.row(align=True) row = layout.row(align=True)
+3 -7
View File
@@ -132,14 +132,10 @@ class Clash(bonsai.core.tool.Clash):
@classmethod @classmethod
def look_at(cls, target: Vector, location: Vector) -> None: def look_at(cls, target: Vector, location: Vector) -> None:
camera_location = location camera_location = location
area = tool.Blender.get_view3d_area() space = tool.Blender.get_view3d_space()
region = next(region for region in area.regions if region.type == "WINDOW") assert space and space.region_3d
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.region_3d.view_location = target 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.region_3d.view_distance = (camera_location - target).length
space.shading.show_xray = True space.shading.show_xray = True
+18 -5
View File
@@ -29,7 +29,7 @@ import ifcopenshell.geom
import ifcopenshell.util.selector import ifcopenshell.util.selector
from logging import Logger from logging import Logger
from typing import Literal, TypedDict, Union from typing import Literal, TypedDict, Union
from typing_extensions import NotRequired from typing_extensions import NotRequired, assert_never
class ClashSource(TypedDict): class ClashSource(TypedDict):
@@ -61,7 +61,7 @@ class ClashSet(TypedDict):
a: list[ClashSource] a: list[ClashSource]
b: NotRequired[list[ClashSource]] b: NotRequired[list[ClashSource]]
mode: Literal["intersection", "collision", "clearance"] mode: Literal["intersection", "collision", "clearance"]
# Added during clash. # Clash results, added during clash.
clashes: NotRequired[dict[str, ClashResult]] clashes: NotRequired[dict[str, ClashResult]]
# intersection, clearance modes. # intersection, clearance modes.
check_all: NotRequired[bool] check_all: NotRequired[bool]
@@ -74,7 +74,7 @@ class ClashSet(TypedDict):
class ClashGroup(TypedDict): class ClashGroup(TypedDict):
elements: dict elements: dict[str, ifcopenshell.entity_instance]
objects: dict objects: dict
@@ -110,6 +110,7 @@ class Clasher:
mode = clash_set["mode"] mode = clash_set["mode"]
if mode == "intersection": if mode == "intersection":
assert "tolerance" in clash_set and "check_all" in clash_set
results = self.tree.clash_intersection_many( results = self.tree.clash_intersection_many(
list(self.groups["a"]["elements"].values()), list(self.groups["a"]["elements"].values()),
list(self.groups[b]["elements"].values()), list(self.groups[b]["elements"].values()),
@@ -117,12 +118,14 @@ class Clasher:
check_all=clash_set["check_all"], check_all=clash_set["check_all"],
) )
elif mode == "collision": elif mode == "collision":
assert "allow_touching" in clash_set
results = self.tree.clash_collision_many( results = self.tree.clash_collision_many(
list(self.groups["a"]["elements"].values()), list(self.groups["a"]["elements"].values()),
list(self.groups[b]["elements"].values()), list(self.groups[b]["elements"].values()),
allow_touching=clash_set["allow_touching"], allow_touching=clash_set["allow_touching"],
) )
elif mode == "clearance": elif mode == "clearance":
assert "clearance" in clash_set and "check_all" in clash_set
results = self.tree.clash_clearance_many( results = self.tree.clash_clearance_many(
list(self.groups["a"]["elements"].values()), list(self.groups["a"]["elements"].values()),
list(self.groups[b]["elements"].values()), list(self.groups[b]["elements"].values()),
@@ -130,7 +133,7 @@ class Clasher:
check_all=clash_set["check_all"], check_all=clash_set["check_all"],
) )
else: else:
assert False, f"Unexpected mode '{mode}'." assert_never(mode)
processed_results: dict[str, ClashResult] = {} processed_results: dict[str, ClashResult] = {}
for result in results: for result in results:
@@ -144,7 +147,7 @@ class Clasher:
b_ifc_class=element2.is_a(), b_ifc_class=element2.is_a(),
a_name=element1.get_argument(2), a_name=element1.get_argument(2),
b_name=element2.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), p1=list(result.p1),
p2=list(result.p2), p2=list(result.p2),
distance=result.distance, distance=result.distance,
@@ -173,10 +176,14 @@ class Clasher:
ifc_file: ifcopenshell.file, ifc_file: ifcopenshell.file,
source: ClashSource, source: ClashSource,
) -> None: ) -> None:
"""Process filters, add tree and group elements."""
assert self.tree
mode = source.get("mode") mode = source.get("mode")
selector = source.get("selector") selector = source.get("selector")
start = time.time() start = time.time()
self.settings.logger.info("Creating iterator") self.settings.logger.info("Creating iterator")
# Process filters.
if not mode or mode == "a" or not selector: if not mode or mode == "a" or not selector:
elements = set(ifc_file.by_type("IfcElement")) elements = set(ifc_file.by_type("IfcElement"))
elements -= set(ifc_file.by_type("IfcFeatureElement")) elements -= set(ifc_file.by_type("IfcFeatureElement"))
@@ -186,11 +193,15 @@ class Clasher:
elements -= set(ifcopenshell.util.selector.filter_elements(ifc_file, selector)) elements -= set(ifcopenshell.util.selector.filter_elements(ifc_file, selector))
elif mode == "i": elif mode == "i":
elements = set(ifcopenshell.util.selector.filter_elements(ifc_file, selector)) elements = set(ifcopenshell.util.selector.filter_elements(ifc_file, selector))
else:
assert_never(mode)
iterator = ifcopenshell.geom.iterator( iterator = ifcopenshell.geom.iterator(
self.geom_settings, ifc_file, multiprocessing.cpu_count(), include=elements self.geom_settings, ifc_file, multiprocessing.cpu_count(), include=elements
) )
self.settings.logger.info(f"Iterator creation finished {time.time() - start}") self.settings.logger.info(f"Iterator creation finished {time.time() - start}")
# Add tree elements.
start = time.time() start = time.time()
self.logger.info(f"Adding objects {name} ({len(elements)} elements)") self.logger.info(f"Adding objects {name} ({len(elements)} elements)")
assert iterator.initialize() assert iterator.initialize()
@@ -200,6 +211,8 @@ class Clasher:
if not iterator.next(): if not iterator.next():
break break
self.logger.info(f"Tree finished {time.time() - start}") self.logger.info(f"Tree finished {time.time() - start}")
# Add group elements.
start = time.time() start = time.time()
self.groups[name]["elements"].update({e.GlobalId: e for e in elements}) self.groups[name]["elements"].update({e.GlobalId: e for e in elements})
self.logger.info(f"Element metadata finished {time.time() - start}") self.logger.info(f"Element metadata finished {time.time() - start}")
@@ -28,7 +28,7 @@ from ..entity_instance import entity_instance
from . import has_occ 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: if TYPE_CHECKING:
from OCC.Core import TopoDS from OCC.Core import TopoDS
@@ -409,13 +409,13 @@ class tree(ifcopenshell_wrapper.tree):
set_b: Iterable[entity_instance], set_b: Iterable[entity_instance],
tolerance: float = 0.002, tolerance: float = 0.002,
check_all: bool = True, 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] 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) return ifcopenshell_wrapper.tree.clash_intersection_many(*args)
def clash_collision_many( def clash_collision_many(
self, set_a: Iterable[entity_instance], set_b: Iterable[entity_instance], allow_touching=False 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] 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) return ifcopenshell_wrapper.tree.clash_collision_many(*args)
@@ -425,7 +425,7 @@ class tree(ifcopenshell_wrapper.tree):
set_b: Iterable[entity_instance], set_b: Iterable[entity_instance],
clearance: float = 0.05, clearance: float = 0.05,
check_all: bool = False, 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] 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) return ifcopenshell_wrapper.tree.clash_clearance_many(*args)