diff --git a/plotpy/items/image/filter.py b/plotpy/items/image/filter.py index 6b1915f..7d1ac64 100644 --- a/plotpy/items/image/filter.py +++ b/plotpy/items/image/filter.py @@ -326,9 +326,9 @@ def draw_image( cy = canvasRect.top() sx = (x1 - x0) / (W - 1) sy = (y1 - y0) / (H - 1) - # tr1 = tr(x0,y0)*scale(sx,sy)*tr(-cx,-cy) - tr = np.matrix([[sx, 0, x0 - cx * sx], [0, sy, y0 - cy * sy], [0, 0, 1]], float) - mat = self.image.tr * tr + # tr1 = tr(x0,y0)@scale(sx,sy)@tr(-cx,-cy) + tr = np.array([[sx, 0, x0 - cx * sx], [0, sy, y0 - cy * sy], [0, 0, 1]], float) + mat = self.image.tr @ tr xytr = x - self.image.x[0], y - self.image.y[0], src_rect diff --git a/plotpy/items/image/transform.py b/plotpy/items/image/transform.py index 96a2ffd..1b483b2 100644 --- a/plotpy/items/image/transform.py +++ b/plotpy/items/image/transform.py @@ -110,7 +110,7 @@ def set_rotation_point(self, x, y, rotation_point_move_with_shape=True): self.rotation_point = colvector(x, y) def set_rotation_point_to_center(self): - handles = self.itr * self.points + handles = self.itr @ self.points center = handles.sum(axis=1) / 4 self.set_rotation_point( center.item(0), center.item(1), rotation_point_move_with_shape=True @@ -153,7 +153,7 @@ def get_pixel_coordinates(self, xplot: float, yplot: float) -> tuple[float, floa Returns: Pixel coordinates """ - v = self.tr * colvector(xplot, yplot) + v = self.tr @ colvector(xplot, yplot) xpixel, ypixel, _ = v[:, 0] return xpixel, ypixel @@ -167,8 +167,8 @@ def get_plot_coordinates(self, xpixel: float, ypixel: float) -> tuple[float, flo Returns: Plot coordinates """ - v0 = self.itr * colvector(xpixel, ypixel) - xplot, yplot, _ = v0[:, 0].A.ravel() + v0 = self.itr @ colvector(xpixel, ypixel) + xplot, yplot, _ = v0[:, 0].ravel() return xplot, yplot def get_x_values(self, i0: int, i1: int) -> np.ndarray: @@ -181,10 +181,10 @@ def get_x_values(self, i0: int, i1: int) -> np.ndarray: Returns: X values corresponding to the given pixel indexes """ - v0 = self.itr * colvector(i0, 0) - x0, _y0, _ = v0[:, 0].A.ravel() - v1 = self.itr * colvector(i1, 0) - x1, _y1, _ = v1[:, 0].A.ravel() + v0 = self.itr @ colvector(i0, 0) + x0, _y0, _ = v0[:, 0].ravel() + v1 = self.itr @ colvector(i1, 0) + x1, _y1, _ = v1[:, 0].ravel() return np.linspace(x0, x1, i1 - i0) def get_y_values(self, j0: int, j1: int) -> np.ndarray: @@ -197,10 +197,10 @@ def get_y_values(self, j0: int, j1: int) -> np.ndarray: Returns: Y values corresponding to the given pixel indexes """ - v0 = self.itr * colvector(0, j0) - _x0, y0, _ = v0[:, 0].A.ravel() - v1 = self.itr * colvector(0, j1) - _x1, y1, _ = v1[:, 0].A.ravel() + v0 = self.itr @ colvector(0, j0) + _x0, y0, _ = v0[:, 0].ravel() + v1 = self.itr @ colvector(0, j1) + _x1, y1, _ = v1[:, 0].ravel() return np.linspace(y0, y1, j1 - j0) def get_r_values(self, i0, i1, j0, j1, flag_circle=False): @@ -216,10 +216,10 @@ def get_r_values(self, i0, i1, j0, j1, flag_circle=False): Returns: Radial values corresponding to the given pixel indexes """ - v0 = self.itr * colvector(i0, j0) - x0, y0, _ = v0[:, 0].A.ravel() - v1 = self.itr * colvector(i1, j1) - x1, y1, _ = v1[:, 0].A.ravel() + v0 = self.itr @ colvector(i0, j0) + x0, y0, _ = v0[:, 0].ravel() + v1 = self.itr @ colvector(i1, j1) + x1, y1, _ = v1[:, 0].ravel() if flag_circle: r = abs(y1 - y0) else: @@ -238,8 +238,8 @@ def get_closest_coordinates(self, x: float, y: float) -> tuple[float, float]: tuple[float, float]: Closest coordinates """ xi, yi = self.get_closest_indexes(x, y) - v = self.itr * colvector(xi, yi) - x, y, _ = v[:, 0].A.ravel() + v = self.itr @ colvector(xi, yi) + x, y, _ = v[:, 0].ravel() return x, y def update_border(self) -> None: @@ -276,9 +276,9 @@ def draw_image( cy = canvasRect.top() sx = (x1 - x0) / (W - 1) sy = (y1 - y0) / (H - 1) - # tr1 = tr(x0,y0)*scale(sx,sy)*tr(-cx,-cy) - tr = np.matrix([[sx, 0, x0 - cx * sx], [0, sy, y0 - cy * sy], [0, 0, 1]], float) - mat = self.tr * tr + # tr1 = tr(x0,y0)@scale(sx,sy)@tr(-cx,-cy) + tr = np.array([[sx, 0, x0 - cx * sx], [0, sy, y0 - cy * sy], [0, 0, 1]], float) + mat = self.tr @ tr dst_rect = tuple([int(i) for i in dst_rect]) dest = _scale_tr( @@ -343,7 +343,7 @@ def export_roi( (ys1 - ys0) / float(yd1 - yd0), ) - mat = self.tr * (translate(xs0, ys0) * scale(xscale, yscale)) + mat = self.tr @ (translate(xs0, ys0) @ scale(xscale, yscale)) x0, y0, x1, y1 = self.get_crop_coordinates() xd0 = max([xd0, xd0 + int((x0 - xs0) / xscale)]) @@ -380,7 +380,7 @@ def move_local_point_to(self, handle: int, pos: QPointF, ctrl: bool = None) -> N return x0, y0, angle, dx, dy, hflip, vflip = self.get_transform() nx, ny = canvas_to_axes(self, pos) - handles = self.itr * self.points + handles = self.itr @ self.points p0 = colvector(nx, ny) if self.can_rotate(): if self.rotation_point is None: @@ -393,9 +393,9 @@ def move_local_point_to(self, handle: int, pos: QPointF, ctrl: bool = None) -> N angle = float(angle + a1 - a0) tr1 = translate(-self.rotation_point[0], -self.rotation_point[1]) rot = rotate(a1 - a0) - tr = tr1.I * rot * tr1 + tr = np.linalg.inv(tr1) @ rot @ tr1 vc = colvector(x0, y0) - new_vc = tr.A.dot(vc) + new_vc = tr.dot(vc) x0, y0 = new_vc[0], new_vc[1] if self.plot(): self.plot().SIG_ITEM_ROTATED.emit(self, angle) @@ -466,9 +466,9 @@ def rotate_local_shape(self, old_pos, new_pos): angle = float(angle) tr1 = translate(-self.rotation_point[0], -self.rotation_point[1]) rot = rotate(a1 - a0) - tr = tr1.I * rot * tr1 + tr = np.linalg.inv(tr1) @ rot @ tr1 vc = colvector(x0, y0) - new_vc = tr * vc + new_vc = tr @ vc x0, y0 = float(new_vc[0]), float(new_vc[1]) if self.plot(): self.plot().SIG_ITEM_ROTATED.emit(self, angle) @@ -506,9 +506,9 @@ def rotate_with_arrows(self, dangle): tr1 = translate(-self.rotation_point[0], -self.rotation_point[1]) rot = rotate(dangle) - tr = tr1.I * rot * tr1 + tr = np.linalg.inv(tr1) @ rot @ tr1 vc = colvector(x0, y0) - new_vc = tr * vc + new_vc = tr @ vc x0, y0 = float(new_vc[0]), float(new_vc[1]) new_angle = angle0 + dangle self.set_transform(x0, y0, angle0 + dangle, dx, dy, hflip, vflip) @@ -542,7 +542,7 @@ def resize_with_selection(self, zoom_dx, zoom_dy): if self.rotation_point is None: self.set_rotation_point_to_center() x0, y0, angle, dx, dy, hflip, vflip = self.get_transform() - handles = self.itr * self.points + handles = self.itr @ self.points center = handles.sum(axis=1) / 4 if self.rotation_point_move_with_shape: self.rotation_point[0] = ( @@ -567,9 +567,9 @@ def rotate_with_selection(self, angle): dangle = float(angle - angle0) tr1 = translate(-self.rotation_point[0], -self.rotation_point[1]) rot = rotate(dangle) - tr = tr1.I * rot * tr1 + tr = np.linalg.inv(tr1) @ rot @ tr1 vc = colvector(x0, y0) - new_vc = tr * vc + new_vc = tr @ vc x0, y0 = float(new_vc[0]), float(new_vc[1]) self.set_transform(x0, y0, angle, dx, dy, hflip, vflip) @@ -595,8 +595,8 @@ def set_transform(self, x0, y0, angle, dx=1.0, dy=1.0, hflip=False, vflip=False) yflip = -1.0 if vflip else 1.0 sc = scale(xflip / dx, yflip / dy) tr2 = translate(-x0, -y0) - self.tr = tr1 * sc * rot * tr2 - self.itr = self.tr.I + self.tr = tr1 @ sc @ rot @ tr2 + self.itr = np.linalg.inv(self.tr) self.compute_bounds() def get_transform(self): @@ -623,10 +623,10 @@ def debug_transform(self, pt): # pragma: no cover tr1 = translate(xmin + a, ymin + b) sc = scale(dx, dy) tr2 = translate(-x0, -y0) - p1 = tr1.I * pt - p2 = rot.I * pt - p3 = sc.I * pt - p4 = tr2.I * pt + p1 = np.linalg.inv(tr1) @ pt + p2 = np.linalg.inv(rot) @ pt + p3 = np.linalg.inv(sc) @ pt + p4 = np.linalg.inv(tr2) @ pt print("src=", pt.T) print("tr1:", p1.T) print("tr1+rot:", p2.T) diff --git a/plotpy/mathutils/geometry.py b/plotpy/mathutils/geometry.py index 33894c4..64f94d7 100644 --- a/plotpy/mathutils/geometry.py +++ b/plotpy/mathutils/geometry.py @@ -51,8 +51,8 @@ # =============================================================================== -def translate(tx: float, ty: float) -> np.matrix: - """Return translation matrix (NumPy matrix object) +def translate(tx: float, ty: float) -> np.ndarray: + """Return translation matrix Args: tx: Translation along X-axis @@ -61,11 +61,11 @@ def translate(tx: float, ty: float) -> np.matrix: Returns: Translation matrix """ - return np.matrix([[1, 0, tx], [0, 1, ty], [0, 0, 1]], float) + return np.array([[1, 0, tx], [0, 1, ty], [0, 0, 1]], float) -def scale(sx: float, sy: float) -> np.matrix: - """Return scale matrix (NumPy matrix object) +def scale(sx: float, sy: float) -> np.ndarray: + """Return scale matrix Args: sx: Scale along X-axis @@ -74,11 +74,11 @@ def scale(sx: float, sy: float) -> np.matrix: Returns: Scale matrix """ - return np.matrix([[sx, 0, 0], [0, sy, 0], [0, 0, 1]], float) + return np.array([[sx, 0, 0], [0, sy, 0], [0, 0, 1]], float) -def rotate(alpha: float) -> np.matrix: - """Return rotation matrix (NumPy matrix object) +def rotate(alpha: float) -> np.ndarray: + """Return rotation matrix Args: alpha: Rotation angle (in radians) @@ -86,7 +86,7 @@ def rotate(alpha: float) -> np.matrix: Returns: Rotation matrix """ - return np.matrix( + return np.array( [ [np.cos(alpha), -np.sin(alpha), 0], [np.sin(alpha), np.cos(alpha), 0], @@ -96,17 +96,17 @@ def rotate(alpha: float) -> np.matrix: ) -def colvector(x: float, y: float) -> np.matrix: - """Return vector (NumPy matrix object) from coordinates +def colvector(x: float, y: float) -> np.ndarray: + """Return vector from coordinates Args: x: x-coordinate y: y-coordinate Returns: - Vector (NumPy matrix object) + Vector """ - return np.matrix([x, y, 1]).T + return np.array([x, y, 1]).T # =============================================================================== @@ -129,7 +129,9 @@ def vector_norm(xa: float, ya: float, xb: float, yb: float) -> float: return np.linalg.norm(np.array((xb - xa, yb - ya))) -def vector_projection(dv: np.ndarray, xa: float, ya: float, xb: float, yb: float): +def vector_projection( + dv: np.ndarray, xa: float, ya: float, xb: float, yb: float +) -> np.ndarray: """Return vector projection Args: @@ -159,7 +161,7 @@ def vector_rotation(theta: float, dx: float, dy: float) -> tuple[float, float]: Returns: Tuple of (x, y) coordinates of rotated vector """ - return np.array(rotate(theta) * colvector(dx, dy)).ravel()[:2] + return (rotate(theta) @ colvector(dx, dy)).ravel()[:2] def vector_angle(dx: float, dy: float) -> float: diff --git a/plotpy/tests/unit/test_geometry.py b/plotpy/tests/unit/test_geometry.py index 89d2215..e8647b3 100644 --- a/plotpy/tests/unit/test_geometry.py +++ b/plotpy/tests/unit/test_geometry.py @@ -23,21 +23,21 @@ def test_transform_matrix() -> None: angle = 30.0 vect0 = geom.colvector(x0, y0) # print("vect0:", repr(vect0)) - vect1 = geom.scale(scale_x, scale_y) * vect0 - assert np.allclose(vect1, np.matrix([[2.0], [6.0], [1.0]])) + vect1 = geom.scale(scale_x, scale_y) @ vect0 # print("vect1:", repr(vect1)) - vect2 = geom.translate(delta_x, delta_y) * vect1 - assert np.allclose(vect2, np.matrix([[17.3], [16.4], [1.0]])) + assert np.allclose(vect1, np.array([2.0, 6.0, 1.0])) + vect2 = geom.translate(delta_x, delta_y) @ vect1 # print("vect2:", repr(vect2)) - vect3 = geom.rotate(angle) * vect2 - assert np.allclose(vect3, np.matrix([[18.87226872], [-14.56322332], [1.0]])) + assert np.allclose(vect2, np.array([17.3, 16.4, 1.0])) + vect3 = geom.rotate(angle) @ vect2 # print("vect3:", repr(vect3)) + assert np.allclose(vect3, np.array([18.87226872, -14.56322332, 1.0])) trmat = ( geom.scale(1.0 / scale_x, 1.0 / scale_y) - * geom.translate(-delta_x, -delta_y) - * geom.rotate(-angle) + @ geom.translate(-delta_x, -delta_y) + @ geom.rotate(-angle) ) - vect4 = trmat * vect3 + vect4 = trmat @ vect3 # print("vect4:", repr(vect4)) assert np.allclose(vect0, vect4)