snap: black formatting

This commit is contained in:
Bruno Perdigão
2026-08-22 21:09:36 -03:00
committed by Bruno Perdigão
parent 105d186a34
commit e9c7203c23
2 changed files with 66 additions and 52 deletions
+65 -51
View File
@@ -42,7 +42,6 @@ import bonsai.tool as tool
from bonsai.bim.module.drawing.data import DecoratorData from bonsai.bim.module.drawing.data import DecoratorData
from bonsai.bim.module.drawing.decoration import CutDecorator from bonsai.bim.module.drawing.decoration import CutDecorator
_wireframe_batch_cache: dict[int, dict[str, tuple[GPUBatch, int, list]]] = {} _wireframe_batch_cache: dict[int, dict[str, tuple[GPUBatch, int, list]]] = {}
_wireframe_vert_fmt: GPUVertFormat | None = None _wireframe_vert_fmt: GPUVertFormat | None = None
_triangle_batch_cache: dict[int, tuple[GPUBatch, int]] = {} _triangle_batch_cache: dict[int, tuple[GPUBatch, int]] = {}
@@ -158,6 +157,7 @@ def _get_solid_triangles(obj: bpy.types.Object) -> list[tuple[tuple, tuple, tupl
eval_obj.to_mesh_clear() eval_obj.to_mesh_clear()
return tris return tris
def _get_cut_object_solid_triangles(obj: bpy.types.Object) -> list[tuple[tuple, tuple, tuple]]: def _get_cut_object_solid_triangles(obj: bpy.types.Object) -> list[tuple[tuple, tuple, tuple]]:
""" """
Gets all the triangles from cut decorator fill, in local space Gets all the triangles from cut decorator fill, in local space
@@ -306,6 +306,7 @@ def _get_boundary_features(obj: bpy.types.Object) -> tuple[list[tuple[float, flo
eval_obj.to_mesh_clear() eval_obj.to_mesh_clear()
return verts, edge_pairs return verts, edge_pairs
def _get_cut_object_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]]]):
@@ -322,7 +323,11 @@ def _get_cut_object_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:
return {}, {} return {}, {}
@@ -373,8 +378,6 @@ def _ensure_wireframe_batches(obj: bpy.types.Object) -> dict[str, tuple[GPUBatch
all_vert_coords, edge_pairs = _get_boundary_features(obj) all_vert_coords, edge_pairs = _get_boundary_features(obj)
batches: dict[str, tuple[GPUBatch, int, list]] = {} batches: dict[str, tuple[GPUBatch, int, list]] = {}
# POINTS batch (all wireframe vertices) # POINTS batch (all wireframe vertices)
@@ -410,16 +413,17 @@ 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: list[bpy.types.Object]) -> list[tuple[GPUBatch, Matrix, int]]: 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
encodes its index in the global ``_obj_list`` (slot 0 is reserved for encodes its index in the global ``_obj_list`` (slot 0 is reserved for
the background). The batch is drawn unlit so the object index can be the background). The batch is drawn unlit so the object index can be
read back from the framebuffer. read back from the framebuffer.
Args: Args:
objs_to_raycast: iterable of candidate objects. objs_to_raycast: iterable of candidate objects.
Returns: Returns:
list[tuple[GPUBatch, Matrix, int]]: ``(batch, world_matrix, slot_base)`` list[tuple[GPUBatch, Matrix, int]]: ``(batch, world_matrix, slot_base)``
@@ -446,28 +450,31 @@ def _get_tris_render_ops(objs_to_raycast: list[bpy.types.Object]) -> list[tuple[
slot_base = obj_index + 1 # slot 0 = background slot_base = obj_index + 1 # slot 0 = background
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: bpy.types.Context, event: bpy.types.Event, mouse_read_rect, buffers_list, last_buf, xray_mode) -> tuple[list[dict], bpy.types.Object | None]:
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
cursor (``buffers_list``); otherwise the center pixel of the readback cursor (``buffers_list``); otherwise the center pixel of the readback
region (``last_buf``) is decoded. Every hit object is then ray cast for region (``last_buf``) is decoded. Every hit object is then ray cast for
real to find the exact face, producing one ``Face`` snap per hit. real to find the exact face, producing one ``Face`` snap per hit.
Args: Args:
context: Blender context. context: Blender context.
event: the event carrying the cursor position. event: the event carrying the cursor position.
mouse: ``(mx, read_x, my, read_y)`` cursor and readback origin. mouse: ``(mx, read_x, my, read_y)`` cursor and readback origin.
buffers_list: per-object single-pixel buffers (xray mode only). buffers_list: per-object single-pixel buffers (xray mode only).
last_buf: full readback region buffer (non-xray mode). last_buf: full readback region buffer (non-xray mode).
xray_mode: whether solid xray rendering is active. xray_mode: whether solid xray rendering is active.
Returns: Returns:
tuple[list[dict], bpy.types.Object | None]: the face snaps and the tuple[list[dict], bpy.types.Object | None]: the face snaps and the
closest hit object, or ``([], None)`` when nothing was hit. closest hit object, or ``([], None)`` when nothing was hit.
""" """
global _obj_list global _obj_list
w, h, mx, my, read_x, read_y = mouse_read_rect w, h, mx, my, read_x, read_y = mouse_read_rect
@@ -525,7 +532,7 @@ def _create_tris_snaps(context: bpy.types.Context, event: bpy.types.Event, mouse
"group": "Object", "group": "Object",
"object": hit_obj, "object": hit_obj,
"face_index": face_index, "face_index": face_index,
"is_cut": is_cut_face, # Used later in snap "is_cut": is_cut_face, # Used later in snap
"distance": 9, # High value so it has low priority "distance": 9, # High value so it has low priority
} }
dist = (hit - ray_origin).length dist = (hit - ray_origin).length
@@ -536,24 +543,27 @@ def _create_tris_snaps(context: bpy.types.Context, event: bpy.types.Event, mouse
snaps.append(snap) snaps.append(snap)
return snaps, closest_obj return snaps, closest_obj
def _get_wireframe_render_ops(objs_to_raycast: list[bpy.types.Objects]) -> tuple[list[tuple[GPUBatch, Matrix, int]], list[tuple]]:
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
IDs across all objects, so every vertex and edge gets a unique encoded IDs across all objects, so every vertex and edge gets a unique encoded
ID. Per-object slot ranges are recorded in ``obj_slots`` for decoding. ID. Per-object slot ranges are recorded in ``obj_slots`` for decoding.
Args: Args:
objs_to_raycast: iterable of candidate objects. objs_to_raycast: iterable of candidate objects.
Returns: Returns:
tuple[list[tuple[GPUBatch, Matrix, int]], list[tuple]]: tuple[list[tuple[GPUBatch, Matrix, int]], list[tuple]]:
``(render_ops, obj_slots)`` where ``render_ops`` holds ``(render_ops, obj_slots)`` where ``render_ops`` holds
``(batch, world_matrix, slot_base)`` and each ``obj_slots`` ``(batch, world_matrix, slot_base)`` and each ``obj_slots``
entry is ``(snap_obj, pts_start, n_pts, lines_start, n_lines)``. entry is ``(snap_obj, pts_start, n_pts, lines_start, n_lines)``.
""" """
render_ops: list[tuple[GPUBatch, Matrix, int]] = [] render_ops: list[tuple[GPUBatch, Matrix, int]] = []
obj_slots: list[tuple] = [] # [(snap_obj, pts_start, n_pts, lines_start, n_lines), ...] obj_slots: list[tuple] = [] # [(snap_obj, pts_start, n_pts, lines_start, n_lines), ...]
@@ -589,25 +599,28 @@ def _get_wireframe_render_ops(objs_to_raycast: list[bpy.types.Objects]) -> tuple
return render_ops, obj_slots return render_ops, obj_slots
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. 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.
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
back to a vertex or edge via ``obj_slots``, then builds the candidate back to a vertex or edge via ``obj_slots``, then builds the candidate
snaps (Vertex, Edge, Edge Center, plus endpoint Vertex snaps within the snaps (Vertex, Edge, Edge Center, plus endpoint Vertex snaps within the
snap threshold). snap threshold).
Args: Args:
context: Blender context. context: Blender context.
event: the event carrying the cursor position. event: the event carrying the cursor position.
mouse: ``(mx, read_x, my, read_y)`` cursor and readback origin. mouse: ``(mx, read_x, my, read_y)`` cursor and readback origin.
obj_slots: ``[(snap_obj, pts_start, n_pts, lines_start, n_lines), ...]``. obj_slots: ``[(snap_obj, pts_start, n_pts, lines_start, n_lines), ...]``.
last_buf: full readback region buffer. last_buf: full readback region buffer.
Returns: Returns:
tuple[list[dict], None]: the wireframe snaps, or ``([], None)`` when tuple[list[dict], None]: the wireframe snaps, or ``([], None)`` when
no non-zero pixel is found near the cursor. no non-zero pixel is found near the cursor.
""" """
global _wireframe_batch_cache global _wireframe_batch_cache
w, h, mx, my, read_x, read_y = mouse_read_rect w, h, mx, my, read_x, read_y = mouse_read_rect
@@ -692,7 +705,7 @@ def _create_wireframe_snaps(context: bpy.types.Context, event: bpy.types.Event,
) )
# Edge Center snap (midpoint) # Edge Center snap (midpoint)
mid = (v0 + v1) / 2 # TODO Allow divisions by other values mid = (v0 + v1) / 2 # TODO Allow divisions by other values
mid_proj = tool.Cad.point_on_edge(mid, (ray_target, loc)) mid_proj = tool.Cad.point_on_edge(mid, (ray_target, loc))
mid_dist = (mid - mid_proj).length mid_dist = (mid - mid_proj).length
snaps.append( snaps.append(
@@ -723,6 +736,7 @@ def _create_wireframe_snaps(context: bpy.types.Context, event: bpy.types.Event,
return snaps, None return snaps, None
class Raycast(bonsai.core.tool.Raycast): class Raycast(bonsai.core.tool.Raycast):
offset = 10 offset = 10
mouse_offset = ( mouse_offset = (
@@ -1163,13 +1177,13 @@ class Raycast(bonsai.core.tool.Raycast):
def clear_cache(cls): def clear_cache(cls):
global _wireframe_batch_cache, _wireframe_vert_fmt, _triangle_batch_cache, _triangle_vert_fmt, _encoding_shader, _offscreen, _obj_list global _wireframe_batch_cache, _wireframe_vert_fmt, _triangle_batch_cache, _triangle_vert_fmt, _encoding_shader, _offscreen, _obj_list
_wireframe_batch_cache = {} _wireframe_batch_cache = {}
_wireframe_vert_fmt= None _wireframe_vert_fmt = None
_triangle_batch_cache= {} _triangle_batch_cache = {}
_triangle_vert_fmt= None _triangle_vert_fmt = None
_encoding_shader= None _encoding_shader = None
_offscreen= None _offscreen = None
_obj_list= [] _obj_list = []
@classmethod @classmethod
def ray_cast_by_proximity( def ray_cast_by_proximity(
cls, cls,
+1 -1
View File
@@ -435,7 +435,7 @@ class Snap(bonsai.core.tool.Snap):
detected_snaps.extend(wireframe_snaps) detected_snaps.extend(wireframe_snaps)
# Axis and Plane # Axis and Plane
if tool.Ifc.get(): if tool.Ifc.get():
elevation = tool.Root.get_default_container_elevation() elevation = tool.Root.get_default_container_elevation()
else: else: