Refine freehand exclusion polygons
Store freehand paths as closed polygons with thin outlines and fill the interior when masking, so free-drawn shapes behave like custom rectangles.
This commit is contained in:
+16
-10
@@ -14,7 +14,6 @@ class ExclusionMixin:
|
||||
y = max(0, min(self.preview_img.height - 1, int(event.y)))
|
||||
if mode == "free":
|
||||
self._current_stroke = [(x, y)]
|
||||
width = int(getattr(self, "free_draw_width", 14))
|
||||
preview_id = getattr(self, "_stroke_preview_id", None)
|
||||
if preview_id:
|
||||
try:
|
||||
@@ -27,15 +26,13 @@ class ExclusionMixin:
|
||||
x,
|
||||
y,
|
||||
fill="yellow",
|
||||
width=width,
|
||||
width=2,
|
||||
smooth=True,
|
||||
capstyle="round",
|
||||
joinstyle="round",
|
||||
)
|
||||
self._rubber_start = None
|
||||
return
|
||||
x = max(0, min(self.preview_img.width - 1, int(event.x)))
|
||||
y = max(0, min(self.preview_img.height - 1, int(event.y)))
|
||||
self._rubber_start = (x, y)
|
||||
if self._rubber_id:
|
||||
try:
|
||||
@@ -70,13 +67,12 @@ class ExclusionMixin:
|
||||
mode = getattr(self, "exclude_mode", "rect")
|
||||
if mode == "free":
|
||||
stroke = getattr(self, "_current_stroke", None)
|
||||
if stroke and len(stroke) > 1:
|
||||
cleaned = self._compress_stroke(stroke)
|
||||
if len(cleaned) > 1:
|
||||
if stroke and len(stroke) > 2:
|
||||
polygon = self._close_polygon(self._compress_stroke(stroke))
|
||||
if len(polygon) >= 3:
|
||||
shape = {
|
||||
"kind": "stroke",
|
||||
"points": cleaned,
|
||||
"width": int(getattr(self, "free_draw_width", 14)),
|
||||
"kind": "polygon",
|
||||
"points": polygon,
|
||||
}
|
||||
self.exclude_shapes.append(shape)
|
||||
stamper = getattr(self, "_stamp_shape_on_mask", None)
|
||||
@@ -190,5 +186,15 @@ class ExclusionMixin:
|
||||
compressed.append(point)
|
||||
return compressed
|
||||
|
||||
@staticmethod
|
||||
def _close_polygon(points: list[tuple[int, int]]) -> list[tuple[int, int]]:
|
||||
"""Ensure the polygon is closed by repeating the start if necessary."""
|
||||
if len(points) < 3:
|
||||
return points
|
||||
closed = list(points)
|
||||
if closed[0] != closed[-1]:
|
||||
closed.append(closed[0])
|
||||
return closed
|
||||
|
||||
|
||||
__all__ = ["ExclusionMixin"]
|
||||
|
||||
Reference in New Issue
Block a user