From 348a96b12c62a8e50fe3fd57f0c6895aa3589e84 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Fri, 8 Nov 2024 18:14:14 +0100 Subject: [PATCH] Place pins arbitrarily (not just image corners) --- examples/pattern.py | 2 +- pyglet_cornerpin/cornerpin.py | 50 +++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/examples/pattern.py b/examples/pattern.py index dbdddc2..91df0bc 100644 --- a/examples/pattern.py +++ b/examples/pattern.py @@ -29,7 +29,7 @@ def on_key_press(symbol, modifiers): exit() -pins = PygletCornerPin(window) +pins = PygletCornerPin(window, source_points=[[100,100], [700,100], [100,500], [300,300]]) # event handlers for dragging: window.push_handlers(pins) diff --git a/pyglet_cornerpin/cornerpin.py b/pyglet_cornerpin/cornerpin.py index 8daec18..62d127c 100644 --- a/pyglet_cornerpin/cornerpin.py +++ b/pyglet_cornerpin/cornerpin.py @@ -11,6 +11,7 @@ incidently so won't really hurt performance. import pyglet from typing import Optional import logging +import copy def adj(m): # Compute the adjugate of m return [ @@ -63,8 +64,17 @@ def general2DProjection( d = basisToPoints(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d) return multmm(d, adj(s)) -def transform2d(w, h, x1, y1, x2, y2, x3, y3, x4, y4): - t = general2DProjection(0, 0, x1, y1, w, 0, x2, y2, 0, h, x3, y3, w, h, x4, y4) +def transform2d_wh(w, h, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d): + """ + Transform the image corners based on width and height of the image + """ + return transform2d(0, 0, x1d, y1d, w, 0, x2d, y2d, 0, h, x3d, y3d, w, h, x4d, y4d) + +def transform2d(x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d): + """ + Transform the image based on 4 arbitrarily placed pins + """ + t = general2DProjection(x1s, y1s, x1d, y1d, x2s, y2s, x2d, y2d, x3s, y3s, x3d, y3d, x4s, y4s, x4d, y4d) for i in range(9): t[i] = t[i] / t[8] @@ -77,7 +87,7 @@ def transform2d(w, h, x1, y1, x2, y2, x3, y3, x4, y4): # Below are all pyglet specific functions class PygletCornerPin(pyglet.event.EventDispatcher): - def __init__(self, window: pyglet.window.Window, corners: Optional[list[list[float]]] = None) -> None: + def __init__(self, window: pyglet.window.Window, corners: Optional[list[list[float]]] = None, source_points: Optional[list[list[float]]] = None) -> None: """ Creates CornerPin utility for a given Pyglet window. If not given, corners default to the bottom left, bottom right, top left, top right corners of the window (i.e. no transform) @@ -85,21 +95,23 @@ class PygletCornerPin(pyglet.event.EventDispatcher): Do not forget to register event handlers by running `window.register_handlers(pins)`. """ self.window = window - self.corners = corners if corners else [ + self.source_points = source_points if source_points else [ [0, 0], [self.window.width, 0], [0, self.window.height], [self.window.width, self.window.height], ] + self.pin_positions = corners if corners else copy.deepcopy(self.source_points) + self.batch = pyglet.graphics.Batch() self.dragging: Optional[int] = None self.handles = [ - pyglet.shapes.Arc(c[0],c[1],20, thickness=2, color=(0,0,255,255), batch=self.batch) for c in self.corners + pyglet.shapes.Arc(c[0],c[1],20, thickness=2, color=(0,0,255,255), batch=self.batch) for c in self.pin_positions ] self.current_corner = None def update_handles(self): - for i, c in enumerate(self.corners): + for i, c in enumerate(self.pin_positions): self.handles[i].x = c[0] self.handles[i].y = c[1] @@ -109,14 +121,12 @@ class PygletCornerPin(pyglet.event.EventDispatcher): """ self.batch.draw() - def transform2d_matrix(self, x1, y1, x2, y2, x3, y3, x4, y4): + def transform2d_matrix(self,x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d): """ Calculate the transform matrix """ t = transform2d( - self.window.width, - self.window.height, - x1, y1, x2, y2, x3, y3, x4, y4 ) + x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d) return pyglet.math.Mat4(t) # event handlers @@ -126,8 +136,8 @@ class PygletCornerPin(pyglet.event.EventDispatcher): currentcorner = None dist = r * r for i in range(4): - dx = x - self.corners[i][0] - dy = y - self.corners[i][1] + dx = x - self.pin_positions[i][0] + dy = y - self.pin_positions[i][1] if dist > dx**2 + dy ** 2: dist = dx**2 + dy ** 2 currentcorner = i @@ -139,15 +149,15 @@ class PygletCornerPin(pyglet.event.EventDispatcher): if self.dragging is None: return pyglet.event.EVENT_UNHANDLED self.dragging = None - logging.debug(f"Corner pins set to {self.corners}") + logging.debug(f"Corner pins set to {self.pin_positions}") return pyglet.event.EVENT_HANDLED def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): if self.dragging is None: return pyglet.event.EVENT_UNHANDLED - self.corners[self.dragging][0] = x - self.corners[self.dragging][1] = y + self.pin_positions[self.dragging][0] = x + self.pin_positions[self.dragging][1] = y self.update_view() def on_key_release(self, symbol: int, modifiers: int): @@ -186,15 +196,15 @@ class PygletCornerPin(pyglet.event.EventDispatcher): base *= 2 if symbol == pyglet.window.key.RIGHT: - self.corners[self.current_corner][0] += base + self.pin_positions[self.current_corner][0] += base if symbol == pyglet.window.key.LEFT: - self.corners[self.current_corner][0] -= base + self.pin_positions[self.current_corner][0] -= base if symbol == pyglet.window.key.UP: - self.corners[self.current_corner][1] += base + self.pin_positions[self.current_corner][1] += base if symbol == pyglet.window.key.DOWN: - self.corners[self.current_corner][1] -= base + self.pin_positions[self.current_corner][1] -= base self.update_view() def update_view(self): - self.window.view = self.transform2d_matrix(*[x for c in self.corners for x in c]) + self.window.view = self.transform2d_matrix(*[x for c in self.source_points for x in c], *[x for c in self.pin_positions for x in c])