mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 17:57:02 +00:00
snap: typing
This commit is contained in:
@@ -49,7 +49,7 @@ _triangle_batch_cache: dict[int, tuple[GPUBatch, int]] = {}
|
|||||||
_triangle_vert_fmt: GPUVertFormat | None = None
|
_triangle_vert_fmt: GPUVertFormat | None = None
|
||||||
_encoding_shader: gpu.types.GPUShader | None = None
|
_encoding_shader: gpu.types.GPUShader | None = None
|
||||||
_offscreen: GPUOffScreen | None = None
|
_offscreen: GPUOffScreen | None = None
|
||||||
_obj_list: list[bpy.types.Object] = []
|
_obj_list: list[[bpy.types.Object, bool]] = []
|
||||||
|
|
||||||
_SNAP_RADIUS_PX = 10 # half-size of the readback region around the cursor
|
_SNAP_RADIUS_PX = 10 # half-size of the readback region around the cursor
|
||||||
|
|
||||||
@@ -123,11 +123,14 @@ def _find_closest_wireframe_pixel(buffer_data, cx, cy):
|
|||||||
return best
|
return best
|
||||||
|
|
||||||
|
|
||||||
def _get_solid_triangles(obj: bpy.types.Object):
|
def _get_solid_triangles(obj: bpy.types.Object) -> list[tuple[tuple, tuple, tuple]]:
|
||||||
"""Return the list of triangles for *obj* in **local** space.
|
"""Return the list of triangles for *obj* in **local** space.
|
||||||
|
|
||||||
Uses evaluated mesh so that modifiers are respected.
|
Uses evaluated mesh so that modifiers are respected.
|
||||||
The world matrix is applied separately in the shader.
|
The world matrix is applied separately in the shader.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
tris: list[tuple[tuple, tuple, tuple]] = []
|
||||||
"""
|
"""
|
||||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
eval_obj = obj.evaluated_get(depsgraph)
|
eval_obj = obj.evaluated_get(depsgraph)
|
||||||
@@ -135,7 +138,7 @@ def _get_solid_triangles(obj: bpy.types.Object):
|
|||||||
if not mesh or not mesh.vertices:
|
if not mesh or not mesh.vertices:
|
||||||
if mesh:
|
if mesh:
|
||||||
eval_obj.to_mesh_clear()
|
eval_obj.to_mesh_clear()
|
||||||
return [], []
|
return []
|
||||||
|
|
||||||
mesh.calc_loop_triangles()
|
mesh.calc_loop_triangles()
|
||||||
|
|
||||||
@@ -165,7 +168,7 @@ def _get_cut_object_solid_triangles(obj: bpy.types.Object) -> list[tuple[tuple,
|
|||||||
"""
|
"""
|
||||||
model_props = tool.Model.get_model_props()
|
model_props = tool.Model.get_model_props()
|
||||||
if not (element := tool.Ifc.get_entity(obj)):
|
if not (element := tool.Ifc.get_entity(obj)):
|
||||||
return {}, {}
|
return []
|
||||||
if model_props.show_cut_decorator_fill and element.id() in DecoratorData.fill_cache:
|
if model_props.show_cut_decorator_fill and element.id() in DecoratorData.fill_cache:
|
||||||
tris_co: list[tuple[tuple, tuple, tuple]] = []
|
tris_co: list[tuple[tuple, tuple, tuple]] = []
|
||||||
for color, verts_and_tris in DecoratorData.fill_cache[element.id()].items():
|
for color, verts_and_tris in DecoratorData.fill_cache[element.id()].items():
|
||||||
@@ -178,7 +181,7 @@ def _get_cut_object_solid_triangles(obj: bpy.types.Object) -> list[tuple[tuple,
|
|||||||
return tris_co
|
return tris_co
|
||||||
|
|
||||||
|
|
||||||
def _ensure_triangle_batches(obj: bpy.types.Object) -> tuple[GPUBatch, int] | None:
|
def _ensure_triangle_batches(obj: bpy.types.Object) -> tuple[GPUBatch | None, bool]:
|
||||||
"""Build (or fetch from cache) a TRIANGLES batch for *obj*.
|
"""Build (or fetch from cache) a TRIANGLES batch for *obj*.
|
||||||
|
|
||||||
When in drawing view, creates the triangles from cut decorator fill.
|
When in drawing view, creates the triangles from cut decorator fill.
|
||||||
@@ -206,9 +209,7 @@ def _ensure_triangle_batches(obj: bpy.types.Object) -> tuple[GPUBatch, int] | No
|
|||||||
|
|
||||||
tris = []
|
tris = []
|
||||||
if CutDecorator.installed:
|
if CutDecorator.installed:
|
||||||
print(obj)
|
|
||||||
tris = _get_cut_object_solid_triangles(obj)
|
tris = _get_cut_object_solid_triangles(obj)
|
||||||
print(tris)
|
|
||||||
if tris:
|
if tris:
|
||||||
is_cut_face = True
|
is_cut_face = True
|
||||||
if not tris and (hasattr(obj.data, "polygons") and len(obj.data.polygons) > 0):
|
if not tris and (hasattr(obj.data, "polygons") and len(obj.data.polygons) > 0):
|
||||||
@@ -241,7 +242,7 @@ def _ensure_triangle_batches(obj: bpy.types.Object) -> tuple[GPUBatch, int] | No
|
|||||||
return batch, is_cut_face
|
return batch, is_cut_face
|
||||||
|
|
||||||
|
|
||||||
def _get_boundary_features(obj: bpy.types.Object):
|
def _get_boundary_features(obj: bpy.types.Object) -> tuple[list[tuple[float, float, float]], list[tuple[tuple, tuple]]]:
|
||||||
"""
|
"""
|
||||||
Uses bmesh on the **evaluated** mesh so that modifiers are respected.
|
Uses bmesh on the **evaluated** mesh so that modifiers are respected.
|
||||||
Gets only edges that are not in a face and vertices that are not on and edge
|
Gets only edges that are not in a face and vertices that are not on and edge
|
||||||
@@ -305,7 +306,7 @@ def _get_boundary_features(obj: bpy.types.Object):
|
|||||||
eval_obj.to_mesh_clear()
|
eval_obj.to_mesh_clear()
|
||||||
return verts, edge_pairs
|
return verts, edge_pairs
|
||||||
|
|
||||||
def _get_cut_objects_features(
|
def _get_cut_object_features(
|
||||||
obj: bpy.types.Object,
|
obj: bpy.types.Object,
|
||||||
) -> (list[tuple[float, float, float]], list[tuple[tuple[float, float, float], tuple[float, float, float]]]):
|
) -> (list[tuple[float, float, float]], list[tuple[tuple[float, float, float], tuple[float, float, float]]]):
|
||||||
"""Return ``(all_vert_coords, edge_pairs)`` for *obj*.
|
"""Return ``(all_vert_coords, edge_pairs)`` for *obj*.
|
||||||
@@ -320,7 +321,7 @@ def _get_cut_objects_features(
|
|||||||
"""
|
"""
|
||||||
model_props = tool.Model.get_model_props()
|
model_props = tool.Model.get_model_props()
|
||||||
if not (element := tool.Ifc.get_entity(obj)):
|
if not (element := tool.Ifc.get_entity(obj)):
|
||||||
return {}, {}
|
return [], []
|
||||||
if model_props.show_cut_decorator and element.id() in DecoratorData.cut_cache and (hasattr(obj.data, "polygons") and len(obj.data.polygons) > 0):
|
if model_props.show_cut_decorator and element.id() in DecoratorData.cut_cache and (hasattr(obj.data, "polygons") and len(obj.data.polygons) > 0):
|
||||||
verts, edges = DecoratorData.cut_cache[element.id()]
|
verts, edges = DecoratorData.cut_cache[element.id()]
|
||||||
if not verts or not edges:
|
if not verts or not edges:
|
||||||
@@ -330,7 +331,7 @@ def _get_cut_objects_features(
|
|||||||
|
|
||||||
return verts, edge_pairs
|
return verts, edge_pairs
|
||||||
else:
|
else:
|
||||||
return {}, {}
|
return [], []
|
||||||
|
|
||||||
|
|
||||||
def _ensure_wireframe_batches(obj: bpy.types.Object) -> dict[str, tuple[GPUBatch, int, list]]:
|
def _ensure_wireframe_batches(obj: bpy.types.Object) -> dict[str, tuple[GPUBatch, int, list]]:
|
||||||
@@ -349,7 +350,7 @@ def _ensure_wireframe_batches(obj: bpy.types.Object) -> dict[str, tuple[GPUBatch
|
|||||||
if _wireframe_vert_fmt is None:
|
if _wireframe_vert_fmt is None:
|
||||||
_wireframe_vert_fmt = _create_vert_format()
|
_wireframe_vert_fmt = _create_vert_format()
|
||||||
|
|
||||||
cache_key = id(obj) # tied to obj lifecycle for auto-invalidation
|
cache_key = id(obj)
|
||||||
|
|
||||||
# Cache hit
|
# Cache hit
|
||||||
if cache_key in _wireframe_batch_cache:
|
if cache_key in _wireframe_batch_cache:
|
||||||
@@ -357,8 +358,7 @@ def _ensure_wireframe_batches(obj: bpy.types.Object) -> dict[str, tuple[GPUBatch
|
|||||||
|
|
||||||
if CutDecorator.installed:
|
if CutDecorator.installed:
|
||||||
all_vert_coords, edge_pairs = [], []
|
all_vert_coords, edge_pairs = [], []
|
||||||
v, e = _get_cut_objects_features(obj)
|
v, e = _get_cut_object_features(obj)
|
||||||
print(e)
|
|
||||||
if v and e:
|
if v and e:
|
||||||
all_vert_coords, edge_pairs = v, e
|
all_vert_coords, edge_pairs = v, e
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ def _ensure_wireframe_batches(obj: bpy.types.Object) -> dict[str, tuple[GPUBatch
|
|||||||
_wireframe_batch_cache[cache_key] = batches
|
_wireframe_batch_cache[cache_key] = batches
|
||||||
return batches
|
return batches
|
||||||
|
|
||||||
def _get_tris_render_ops(objs_to_raycast):
|
def _get_tris_render_ops(objs_to_raycast: list[bpy.types.Object]) -> list[tuple[GPUBatch, Matrix, int]]:
|
||||||
"""Build render ops for solid (triangle) objects to raycast.
|
"""Build render ops for solid (triangle) objects to raycast.
|
||||||
|
|
||||||
Each mesh contributes a single TRIANGLES batch and a slot base that
|
Each mesh contributes a single TRIANGLES batch and a slot base that
|
||||||
@@ -447,7 +447,7 @@ def _get_tris_render_ops(objs_to_raycast):
|
|||||||
render_ops.append((batch, snap_obj.matrix_world.copy(), slot_base))
|
render_ops.append((batch, snap_obj.matrix_world.copy(), slot_base))
|
||||||
return render_ops
|
return render_ops
|
||||||
|
|
||||||
def _create_tris_snaps(context, event, mouse_read_rect, buffers_list, last_buf, xray_mode):
|
def _create_tris_snaps(context: bpy.types.Context, event: bpy.types.Event, mouse_read_rect, buffers_list, last_buf, xray_mode) -> tuple[list[dict], bpy.types.Object | None]:
|
||||||
"""Decode the triangle readback buffer(s) into face snaps.
|
"""Decode the triangle readback buffer(s) into face snaps.
|
||||||
|
|
||||||
In xray mode each object is read back as a single pixel under the
|
In xray mode each object is read back as a single pixel under the
|
||||||
@@ -518,7 +518,6 @@ def _create_tris_snaps(context, event, mouse_read_rect, buffers_list, last_buf,
|
|||||||
for obj_index in hits:
|
for obj_index in hits:
|
||||||
obj, is_cut_face = _obj_list[obj_index]
|
obj, is_cut_face = _obj_list[obj_index]
|
||||||
hit_obj, hit, face_index = tool.Raycast.cast_rays_to_single_object(context, event, obj)
|
hit_obj, hit, face_index = tool.Raycast.cast_rays_to_single_object(context, event, obj)
|
||||||
print("IS_CUT", obj, is_cut_face)
|
|
||||||
if hit:
|
if hit:
|
||||||
snap: dict = {
|
snap: dict = {
|
||||||
"point": hit,
|
"point": hit,
|
||||||
@@ -538,7 +537,7 @@ def _create_tris_snaps(context, event, mouse_read_rect, buffers_list, last_buf,
|
|||||||
|
|
||||||
return snaps, closest_obj
|
return snaps, closest_obj
|
||||||
|
|
||||||
def _get_wireframe_render_ops(objs_to_raycast):
|
def _get_wireframe_render_ops(objs_to_raycast: list[bpy.types.Objects]) -> tuple[list[tuple[GPUBatch, Matrix, int]], list[tuple]]:
|
||||||
"""Build render ops for wireframe (non-solid) objects.
|
"""Build render ops for wireframe (non-solid) objects.
|
||||||
|
|
||||||
Boundary points and lines of each object are assigned sequential slot
|
Boundary points and lines of each object are assigned sequential slot
|
||||||
@@ -590,7 +589,7 @@ def _get_wireframe_render_ops(objs_to_raycast):
|
|||||||
|
|
||||||
return render_ops, obj_slots
|
return render_ops, obj_slots
|
||||||
|
|
||||||
def _create_wireframe_snaps(context, event, mouse_read_rect, obj_slots, last_buf):
|
def _create_wireframe_snaps(context: bpy.types.Context, event: bpy.types.Event, mouse_read_rect, obj_slots, last_buf) -> tuple[list[dict], None]:
|
||||||
"""Decode the wireframe readback buffer into vertex/edge snaps.
|
"""Decode the wireframe readback buffer into vertex/edge snaps.
|
||||||
|
|
||||||
Finds the closest non-zero pixel to the cursor, maps its encoded slot ID
|
Finds the closest non-zero pixel to the cursor, maps its encoded slot ID
|
||||||
|
|||||||
Reference in New Issue
Block a user