From 37d589335faa178b6027f5bbf53b773d2aaa00d8 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Thu, 25 Apr 2013 00:29:58 +0200 Subject: [PATCH] app: consolidate all transform API in gimpdisplayshell-transform.[ch] Added complete API for zoom/unzoom (scale and scroll) and rotate/unrotate, with the same set of functions as the existing transform/untransform. Moved some special case functions to the namespaces they belong. --- app/display/gimpcanvasitem.c | 11 +- app/display/gimpdisplayshell-draw.c | 8 +- app/display/gimpdisplayshell-items.c | 12 +- app/display/gimpdisplayshell-rotate.c | 78 ---- app/display/gimpdisplayshell-rotate.h | 41 +- app/display/gimpdisplayshell-selection.c | 24 +- app/display/gimpdisplayshell-transform.c | 557 +++++++++++++++++++++-- app/display/gimpdisplayshell-transform.h | 106 ++++- app/tools/gimpdrawtool.c | 20 +- 9 files changed, 653 insertions(+), 204 deletions(-) diff --git a/app/display/gimpcanvasitem.c b/app/display/gimpcanvasitem.c index 9e1a2603bd..e31644b922 100644 --- a/app/display/gimpcanvasitem.c +++ b/app/display/gimpcanvasitem.c @@ -629,18 +629,12 @@ gimp_canvas_item_transform_xy (GimpCanvasItem *item, gint *ty) { GimpCanvasItemPrivate *private; - gint64 nx; - gint64 ny; g_return_if_fail (GIMP_IS_CANVAS_ITEM (item)); private = GET_PRIVATE (item); - nx = x * private->shell->scale_x - private->shell->offset_x; - ny = y * private->shell->scale_y - private->shell->offset_y; - - *tx = CLAMP (nx, G_MININT, G_MAXINT); - *ty = CLAMP (ny, G_MININT, G_MAXINT); + gimp_display_shell_zoom_xy (private->shell, x, y, tx, ty); } void @@ -656,8 +650,7 @@ gimp_canvas_item_transform_xy_f (GimpCanvasItem *item, private = GET_PRIVATE (item); - *tx = SCALEX (private->shell, x) - private->shell->offset_x; - *ty = SCALEY (private->shell, y) - private->shell->offset_y; + gimp_display_shell_zoom_xy_f (private->shell, x, y, tx, ty); } diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c index 0e0e032c32..408f2ab686 100644 --- a/app/display/gimpdisplayshell-draw.c +++ b/app/display/gimpdisplayshell-draw.c @@ -37,8 +37,8 @@ #include "gimpdisplayshell.h" #include "gimpdisplayshell-draw.h" #include "gimpdisplayshell-render.h" -#include "gimpdisplayshell-rotate.h" #include "gimpdisplayshell-scale.h" +#include "gimpdisplayshell-transform.h" #include "gimpdisplayxfer.h" @@ -149,9 +149,9 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell, gint image_width; gint image_height; - gimp_display_shell_rotate_untransform_bounds (shell, - x, y, x + w, y + h, - &tx1, &ty1, &tx2, &ty2); + gimp_display_shell_unrotate_bounds (shell, + x, y, x + w, y + h, + &tx1, &ty1, &tx2, &ty2); x1 = floor (tx1 - 0.5); y1 = floor (ty1 - 0.5); diff --git a/app/display/gimpdisplayshell-items.c b/app/display/gimpdisplayshell-items.c index e8fe8dd79a..17d63c4797 100644 --- a/app/display/gimpdisplayshell-items.c +++ b/app/display/gimpdisplayshell-items.c @@ -34,7 +34,7 @@ #include "gimpdisplayshell.h" #include "gimpdisplayshell-expose.h" #include "gimpdisplayshell-items.h" -#include "gimpdisplayshell-rotate.h" +#include "gimpdisplayshell-transform.h" /* local function prototypes */ @@ -249,11 +249,11 @@ gimp_display_shell_item_update (GimpCanvasItem *item, cairo_region_get_rectangle (region, i, &rect); - gimp_display_shell_rotate_transform_bounds (shell, - rect.x, rect.y, - rect.x + rect.width, - rect.y + rect.height, - &tx1, &ty1, &tx2, &ty2); + gimp_display_shell_rotate_bounds (shell, + rect.x, rect.y, + rect.x + rect.width, + rect.y + rect.height, + &tx1, &ty1, &tx2, &ty2); x1 = floor (tx1 - 0.5); y1 = floor (ty1 - 0.5); diff --git a/app/display/gimpdisplayshell-rotate.c b/app/display/gimpdisplayshell-rotate.c index 61500695bd..676c5bd4a9 100644 --- a/app/display/gimpdisplayshell-rotate.c +++ b/app/display/gimpdisplayshell-rotate.c @@ -24,8 +24,6 @@ #include "display-types.h" -#include "core/gimp-utils.h" - #include "gimpdisplay.h" #include "gimpdisplayshell.h" #include "gimpdisplayshell-expose.h" @@ -149,79 +147,3 @@ gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell) shell->rotate_untransform = NULL; } } - -void -gimp_display_shell_rotate_transform_bounds (GimpDisplayShell *shell, - gdouble x1, - gdouble y1, - gdouble x2, - gdouble y2, - gdouble *nx1, - gdouble *ny1, - gdouble *nx2, - gdouble *ny2) -{ - gdouble tx1, ty1; - gdouble tx2, ty2; - gdouble tx3, ty3; - gdouble tx4, ty4; - - g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); - - tx1 = x1; - ty1 = y1; - tx2 = x1; - ty2 = y2; - tx3 = x2; - ty3 = y1; - tx4 = x2; - ty4 = y2; - - cairo_matrix_transform_point (shell->rotate_transform, &tx1, &ty1); - cairo_matrix_transform_point (shell->rotate_transform, &tx2, &ty2); - cairo_matrix_transform_point (shell->rotate_transform, &tx3, &ty3); - cairo_matrix_transform_point (shell->rotate_transform, &tx4, &ty4); - - *nx1 = MIN4 (tx1, tx2, tx3, tx4); - *ny1 = MIN4 (ty1, ty2, ty3, ty4); - *nx2 = MAX4 (tx1, tx2, tx3, tx4); - *ny2 = MAX4 (ty1, ty2, ty3, ty4); -} - -void -gimp_display_shell_rotate_untransform_bounds (GimpDisplayShell *shell, - gdouble x1, - gdouble y1, - gdouble x2, - gdouble y2, - gdouble *nx1, - gdouble *ny1, - gdouble *nx2, - gdouble *ny2) -{ - gdouble tx1, ty1; - gdouble tx2, ty2; - gdouble tx3, ty3; - gdouble tx4, ty4; - - g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); - - tx1 = x1; - ty1 = y1; - tx2 = x1; - ty2 = y2; - tx3 = x2; - ty3 = y1; - tx4 = x2; - ty4 = y2; - - cairo_matrix_transform_point (shell->rotate_untransform, &tx1, &ty1); - cairo_matrix_transform_point (shell->rotate_untransform, &tx2, &ty2); - cairo_matrix_transform_point (shell->rotate_untransform, &tx3, &ty3); - cairo_matrix_transform_point (shell->rotate_untransform, &tx4, &ty4); - - *nx1 = MIN4 (tx1, tx2, tx3, tx4); - *ny1 = MIN4 (ty1, ty2, ty3, ty4); - *nx2 = MAX4 (tx1, tx2, tx3, tx4); - *ny2 = MAX4 (ty1, ty2, ty3, ty4); -} diff --git a/app/display/gimpdisplayshell-rotate.h b/app/display/gimpdisplayshell-rotate.h index 99fb0cad8b..82d3cb1719 100644 --- a/app/display/gimpdisplayshell-rotate.h +++ b/app/display/gimpdisplayshell-rotate.h @@ -19,37 +19,18 @@ #define __GIMP_DISPLAY_SHELL_ROTATE_H__ -void gimp_display_shell_rotate (GimpDisplayShell *shell, - gdouble delta); -void gimp_display_shell_rotate_to (GimpDisplayShell *shell, - gdouble value); -void gimp_display_shell_rotate_drag (GimpDisplayShell *shell, - gdouble last_x, - gdouble last_y, - gdouble cur_x, - gdouble cur_y, - gboolean constrain); +void gimp_display_shell_rotate (GimpDisplayShell *shell, + gdouble delta); +void gimp_display_shell_rotate_to (GimpDisplayShell *shell, + gdouble value); +void gimp_display_shell_rotate_drag (GimpDisplayShell *shell, + gdouble last_x, + gdouble last_y, + gdouble cur_x, + gdouble cur_y, + gboolean constrain); -void gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell); - -void gimp_display_shell_rotate_transform_bounds (GimpDisplayShell *shell, - gdouble x1, - gdouble y1, - gdouble x2, - gdouble y2, - gdouble *nx1, - gdouble *ny1, - gdouble *nx2, - gdouble *ny2); -void gimp_display_shell_rotate_untransform_bounds (GimpDisplayShell *shell, - gdouble x1, - gdouble y1, - gdouble x2, - gdouble y2, - gdouble *nx1, - gdouble *ny1, - gdouble *nx2, - gdouble *ny2); +void gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell); #endif /* __GIMP_DISPLAY_SHELL_ROTATE_H__ */ diff --git a/app/display/gimpdisplayshell-selection.c b/app/display/gimpdisplayshell-selection.c index cc48fe8430..0181efde02 100644 --- a/app/display/gimpdisplayshell-selection.c +++ b/app/display/gimpdisplayshell-selection.c @@ -68,7 +68,7 @@ static void selection_undraw (Selection *selection); static void selection_render_mask (Selection *selection); -static void selection_transform_segs (Selection *selection, +static void selection_zoom_segs (Selection *selection, const GimpBoundSeg *src_segs, GimpSegment *dest_segs, gint n_segs); @@ -307,18 +307,18 @@ selection_render_mask (Selection *selection) } static void -selection_transform_segs (Selection *selection, - const GimpBoundSeg *src_segs, - GimpSegment *dest_segs, - gint n_segs) +selection_zoom_segs (Selection *selection, + const GimpBoundSeg *src_segs, + GimpSegment *dest_segs, + gint n_segs) { const gint xclamp = selection->shell->disp_width + 1; const gint yclamp = selection->shell->disp_height + 1; gint i; - gimp_display_shell_transform_segments (selection->shell, - src_segs, dest_segs, n_segs, - 0.0, 0.0); + gimp_display_shell_zoom_segments (selection->shell, + src_segs, dest_segs, n_segs, + 0.0, 0.0); for (i = 0; i < n_segs; i++) { @@ -368,8 +368,8 @@ selection_generate_segs (Selection *selection) if (selection->n_segs_in) { selection->segs_in = g_new (GimpSegment, selection->n_segs_in); - selection_transform_segs (selection, segs_in, - selection->segs_in, selection->n_segs_in); + selection_zoom_segs (selection, segs_in, + selection->segs_in, selection->n_segs_in); selection_render_mask (selection); } @@ -382,8 +382,8 @@ selection_generate_segs (Selection *selection) if (selection->n_segs_out) { selection->segs_out = g_new (GimpSegment, selection->n_segs_out); - selection_transform_segs (selection, segs_out, - selection->segs_out, selection->n_segs_out); + selection_zoom_segs (selection, segs_out, + selection->segs_out, selection->n_segs_out); } else { diff --git a/app/display/gimpdisplayshell-transform.c b/app/display/gimpdisplayshell-transform.c index 11aafdf3ec..f5364fca9d 100644 --- a/app/display/gimpdisplayshell-transform.c +++ b/app/display/gimpdisplayshell-transform.c @@ -35,6 +35,509 @@ #include "gimpdisplayshell-transform.h" +/** + * gimp_display_shell_zoom_coords: + * @shell: a #GimpDisplayShell + * @image_coords: image coordinates + * @display_coords: returns the corresponding display coordinates + * + * Zooms from image coordinates to display coordinates, so that + * objects can be rendered at the correct points on the display. + **/ +void +gimp_display_shell_zoom_coords (const GimpDisplayShell *shell, + const GimpCoords *image_coords, + GimpCoords *display_coords) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (image_coords != NULL); + g_return_if_fail (display_coords != NULL); + + *display_coords = *image_coords; + + display_coords->x = SCALEX (shell, image_coords->x); + display_coords->y = SCALEY (shell, image_coords->y); + + display_coords->x -= shell->offset_x; + display_coords->y -= shell->offset_y; +} + +/** + * gimp_display_shell_unzoom_coords: + * @shell: a #GimpDisplayShell + * @display_coords: display coordinates + * @image_coords: returns the corresponding image coordinates + * + * Zooms from display coordinates to image coordinates, so that + * points on the display can be mapped to points in the image. + **/ +void +gimp_display_shell_unzoom_coords (const GimpDisplayShell *shell, + const GimpCoords *display_coords, + GimpCoords *image_coords) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (display_coords != NULL); + g_return_if_fail (image_coords != NULL); + + *image_coords = *display_coords; + + image_coords->x += shell->offset_x; + image_coords->y += shell->offset_y; + + image_coords->x /= shell->scale_x; + image_coords->y /= shell->scale_y; +} + +/** + * gimp_display_shell_zoom_xy: + * @shell: + * @x: + * @y: + * @nx: + * @ny: + * + * Zooms an image coordinate to a shell coordinate. + **/ +void +gimp_display_shell_zoom_xy (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gint *nx, + gint *ny) +{ + gint64 tx; + gint64 ty; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + tx = x * shell->scale_x - shell->offset_x; + ty = y * shell->scale_y - shell->offset_y; + + tx -= shell->offset_x; + ty -= shell->offset_y; + + /* The projected coordinates might overflow a gint in the case of + * big images at high zoom levels, so we clamp them here to avoid + * problems. + */ + *nx = CLAMP (tx, G_MININT, G_MAXINT); + *ny = CLAMP (ty, G_MININT, G_MAXINT); +} + +/** + * gimp_display_shell_unzoom_xy: + * @shell: a #GimpDisplayShell + * @x: x coordinate in display coordinates + * @y: y coordinate in display coordinates + * @nx: returns x oordinate in image coordinates + * @ny: returns y coordinate in image coordinates + * @round: if %TRUE, round the results to the nearest integer; + * if %FALSE, simply cast them to @gint. + * + * Zoom from display coordinates to image coordinates, so that + * points on the display can be mapped to the corresponding points + * in the image. + **/ +void +gimp_display_shell_unzoom_xy (const GimpDisplayShell *shell, + gint x, + gint y, + gint *nx, + gint *ny, + gboolean round) +{ + gint64 tx; + gint64 ty; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + if (round) + { + tx = SIGNED_ROUND (((gdouble) x + shell->offset_x) / shell->scale_x); + ty = SIGNED_ROUND (((gdouble) y + shell->offset_y) / shell->scale_y); + } + else + { + tx = ((gint64) x + shell->offset_x) / shell->scale_x; + ty = ((gint64) y + shell->offset_y) / shell->scale_y; + } + + *nx = CLAMP (tx, G_MININT, G_MAXINT); + *ny = CLAMP (ty, G_MININT, G_MAXINT); +} + +/** + * gimp_display_shell_zoom_xy_f: + * @shell: a #GimpDisplayShell + * @x: image x coordinate of point + * @y: image y coordinate of point + * @nx: returned shell canvas x coordinate + * @ny: returned shell canvas y coordinate + * + * Zooms from image coordinates to display shell canvas + * coordinates. + **/ +void +gimp_display_shell_zoom_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + *nx = SCALEX (shell, x) - shell->offset_x; + *ny = SCALEY (shell, y) - shell->offset_y; +} + +/** + * gimp_display_shell_unzoom_xy_f: + * @shell: a #GimpDisplayShell + * @x: x coordinate in display coordinates + * @y: y coordinate in display coordinates + * @nx: place to return x coordinate in image coordinates + * @ny: place to return y coordinate in image coordinates + * + * This function is identical to gimp_display_shell_unzoom_xy(), + * except that the input and output coordinates are doubles rather than + * ints, and consequently there is no option related to rounding. + **/ +void +gimp_display_shell_unzoom_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + *nx = (x + shell->offset_x) / shell->scale_x; + *ny = (y + shell->offset_y) / shell->scale_y; +} + +/** + * gimp_display_shell_zoom_segments: + * @shell: a #GimpDisplayShell + * @src_segs: array of segments in image coordinates + * @dest_segs: returns the corresponding segments in display coordinates + * @n_segs: number of segments + * + * Zooms from image coordinates to display coordinates, so that + * objects can be rendered at the correct points on the display. + **/ +void +gimp_display_shell_zoom_segments (const GimpDisplayShell *shell, + const GimpBoundSeg *src_segs, + GimpSegment *dest_segs, + gint n_segs, + gdouble offset_x, + gdouble offset_y) +{ + gint i; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + for (i = 0; i < n_segs ; i++) + { + gdouble x1, x2; + gdouble y1, y2; + + x1 = src_segs[i].x1 + offset_x; + x2 = src_segs[i].x2 + offset_x; + y1 = src_segs[i].y1 + offset_y; + y2 = src_segs[i].y2 + offset_y; + + dest_segs[i].x1 = SCALEX (shell, x1) - shell->offset_x; + dest_segs[i].x2 = SCALEX (shell, x2) - shell->offset_x; + dest_segs[i].y1 = SCALEY (shell, y1) - shell->offset_y; + dest_segs[i].y2 = SCALEY (shell, y2) - shell->offset_y; + } +} + +/** + * gimp_display_shell_rotate_coords: + * @shell: a #GimpDisplayShell + * @image_coords: unrotated display coordinates + * @display_coords: returns the corresponding rotated display coordinates + * + * Rotates from unrotated display coordinates to rotated display + * coordinates, so that objects can be rendered at the correct points + * on the display. + **/ +void +gimp_display_shell_rotate_coords (const GimpDisplayShell *shell, + const GimpCoords *unrotated_coords, + GimpCoords *rotated_coords) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (unrotated_coords != NULL); + g_return_if_fail (rotated_coords != NULL); + + *rotated_coords = *rotated_coords; + + if (shell->rotate_transform) + cairo_matrix_transform_point (shell->rotate_transform, + &rotated_coords->x, + &rotated_coords->y); +} + +/** + * gimp_display_shell_unrotate_coords: + * @shell: a #GimpDisplayShell + * @display_coords: rotated display coordinates + * @image_coords: returns the corresponding unrotated display coordinates + * + * Rotates from rotated display coordinates to unrotated display coordinates. + **/ +void +gimp_display_shell_unrotate_coords (const GimpDisplayShell *shell, + const GimpCoords *rotated_coords, + GimpCoords *unrotated_coords) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (rotated_coords != NULL); + g_return_if_fail (unrotated_coords != NULL); + + *unrotated_coords = *rotated_coords; + + if (shell->rotate_untransform) + cairo_matrix_transform_point (shell->rotate_untransform, + &unrotated_coords->x, + &unrotated_coords->y); +} + +/** + * gimp_display_shell_rotate_xy: + * @shell: + * @x: + * @y: + * @nx: + * @ny: + * + * Rotates an unrotated display coordinate to a rotated shell coordinate. + **/ +void +gimp_display_shell_rotate_xy (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gint *nx, + gint *ny) +{ + gint64 tx; + gint64 ty; + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + if (shell->rotate_transform) + cairo_matrix_transform_point (shell->rotate_transform, &x, &y); + + tx = x; + ty = y; + + /* The projected coordinates might overflow a gint in the case of + * big images at high zoom levels, so we clamp them here to avoid + * problems. + */ + *nx = CLAMP (tx, G_MININT, G_MAXINT); + *ny = CLAMP (ty, G_MININT, G_MAXINT); +} + +/** + * gimp_display_shell_unrotate_xy: + * @shell: a #GimpDisplayShell + * @x: x coordinate in rotated display coordinates + * @y: y coordinate in rotated display coordinates + * @nx: returns x oordinate in unrotated display coordinates + * @ny: returns y coordinate in unrotated display coordinates + * + * Rotate from rotated display coordinates to unrotated display + * coordinates. + **/ +void +gimp_display_shell_unrotate_xy (const GimpDisplayShell *shell, + gint x, + gint y, + gint *nx, + gint *ny) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + if (shell->rotate_untransform) + { + gdouble fx = x; + gdouble fy = y; + + cairo_matrix_transform_point (shell->rotate_untransform, &fy, &fy); + + *nx = CLAMP (fx, G_MININT, G_MAXINT); + *ny = CLAMP (fy, G_MININT, G_MAXINT); + } + else + { + *nx = x; + *ny = y; + } +} + +/** + * gimp_display_shell_rotate_xy_f: + * @shell: a #GimpDisplayShell + * @x: image x coordinate of point + * @y: image y coordinate of point + * @nx: returned shell canvas x coordinate + * @ny: returned shell canvas y coordinate + * + * Rotates from untransformed display coordinates to rotated display + * coordinates. + **/ +void +gimp_display_shell_rotate_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + *nx = x; + *ny = y; + + if (shell->rotate_transform) + cairo_matrix_transform_point (shell->rotate_transform, nx, ny); +} + +/** + * gimp_display_shell_unrotate_xy_f: + * @shell: a #GimpDisplayShell + * @x: x coordinate in rotated display coordinates + * @y: y coordinate in rotated display coordinates + * @nx: place to return x coordinate in unrotated display coordinates + * @ny: place to return y coordinate in unrotated display coordinates + * + * This function is identical to gimp_display_shell_unrotate_xy(), + * except that the input and output coordinates are doubles rather + * than ints. + **/ +void +gimp_display_shell_unrotate_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + g_return_if_fail (nx != NULL); + g_return_if_fail (ny != NULL); + + *nx = x; + *ny = y; + + if (shell->rotate_untransform) + cairo_matrix_transform_point (shell->rotate_untransform, nx, ny); +} + +void +gimp_display_shell_rotate_bounds (GimpDisplayShell *shell, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gdouble *nx1, + gdouble *ny1, + gdouble *nx2, + gdouble *ny2) +{ + + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + if (shell->rotate_transform) + { + gdouble tx1 = x1; + gdouble ty1 = y1; + gdouble tx2 = x1; + gdouble ty2 = y2; + gdouble tx3 = x2; + gdouble ty3 = y1; + gdouble tx4 = x2; + gdouble ty4 = y2; + + cairo_matrix_transform_point (shell->rotate_transform, &tx1, &ty1); + cairo_matrix_transform_point (shell->rotate_transform, &tx2, &ty2); + cairo_matrix_transform_point (shell->rotate_transform, &tx3, &ty3); + cairo_matrix_transform_point (shell->rotate_transform, &tx4, &ty4); + + *nx1 = MIN4 (tx1, tx2, tx3, tx4); + *ny1 = MIN4 (ty1, ty2, ty3, ty4); + *nx2 = MAX4 (tx1, tx2, tx3, tx4); + *ny2 = MAX4 (ty1, ty2, ty3, ty4); + } + else + { + *nx1 = x1; + *ny1 = y1; + *nx2 = x2; + *ny2 = y2; + } +} + +void +gimp_display_shell_unrotate_bounds (GimpDisplayShell *shell, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gdouble *nx1, + gdouble *ny1, + gdouble *nx2, + gdouble *ny2) +{ + g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); + + if (shell->rotate_untransform) + { + gdouble tx1 = x1; + gdouble ty1 = y1; + gdouble tx2 = x1; + gdouble ty2 = y2; + gdouble tx3 = x2; + gdouble ty3 = y1; + gdouble tx4 = x2; + gdouble ty4 = y2; + + cairo_matrix_transform_point (shell->rotate_untransform, &tx1, &ty1); + cairo_matrix_transform_point (shell->rotate_untransform, &tx2, &ty2); + cairo_matrix_transform_point (shell->rotate_untransform, &tx3, &ty3); + cairo_matrix_transform_point (shell->rotate_untransform, &tx4, &ty4); + + *nx1 = MIN4 (tx1, tx2, tx3, tx4); + *ny1 = MIN4 (ty1, ty2, ty3, ty4); + *nx2 = MAX4 (tx1, tx2, tx3, tx4); + *ny2 = MAX4 (ty1, ty2, ty3, ty4); + } + else + { + *nx1 = x1; + *ny1 = y1; + *nx2 = x2; + *ny2 = y2; + } +} + /** * gimp_display_shell_transform_coords: * @shell: a #GimpDisplayShell @@ -126,19 +629,24 @@ gimp_display_shell_transform_xy (const GimpDisplayShell *shell, tx = x * shell->scale_x - shell->offset_x; ty = y * shell->scale_y - shell->offset_y; + tx -= shell->offset_x; + ty -= shell->offset_y; + if (shell->rotate_transform) { gdouble fx = tx; gdouble fy = ty; - cairo_matrix_transform_point (shell->rotate_transform, &fy, &fy); + cairo_matrix_transform_point (shell->rotate_transform, &fx, &fy); tx = fx; ty = fy; } - /* The projected coordinates might overflow a gint in the case of big - images at high zoom levels, so we clamp them here to avoid problems. */ + /* The projected coordinates might overflow a gint in the case of + * big images at high zoom levels, so we clamp them here to avoid + * problems. + */ *nx = CLAMP (tx, G_MININT, G_MAXINT); *ny = CLAMP (ty, G_MININT, G_MAXINT); } @@ -185,8 +693,8 @@ gimp_display_shell_untransform_xy (const GimpDisplayShell *shell, if (round) { - tx = SIGNED_ROUND (((gint64) x + shell->offset_x) / shell->scale_x); - ty = SIGNED_ROUND (((gint64) y + shell->offset_y) / shell->scale_y); + tx = SIGNED_ROUND (((gdouble) x + shell->offset_x) / shell->scale_x); + ty = SIGNED_ROUND (((gdouble) y + shell->offset_y) / shell->scale_y); } else { @@ -339,45 +847,6 @@ gimp_display_shell_untransform_bounds (const GimpDisplayShell *shell, } } -/** - * gimp_display_shell_transform_segments: - * @shell: a #GimpDisplayShell - * @src_segs: array of segments in image coordinates - * @dest_segs: returns the corresponding segments in display coordinates - * @n_segs: number of segments - * - * Transforms from image coordinates to display coordinates, so that - * objects can be rendered at the correct points on the display. - **/ -void -gimp_display_shell_transform_segments (const GimpDisplayShell *shell, - const GimpBoundSeg *src_segs, - GimpSegment *dest_segs, - gint n_segs, - gdouble offset_x, - gdouble offset_y) -{ - gint i; - - g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); - - for (i = 0; i < n_segs ; i++) - { - gdouble x1, x2; - gdouble y1, y2; - - x1 = src_segs[i].x1 + offset_x; - x2 = src_segs[i].x2 + offset_x; - y1 = src_segs[i].y1 + offset_y; - y2 = src_segs[i].y2 + offset_y; - - dest_segs[i].x1 = SCALEX (shell, x1) - shell->offset_x; - dest_segs[i].x2 = SCALEX (shell, x2) - shell->offset_x; - dest_segs[i].y1 = SCALEY (shell, y1) - shell->offset_y; - dest_segs[i].y2 = SCALEY (shell, y2) - shell->offset_y; - } -} - /** * gimp_display_shell_untransform_viewport: * @shell: a #GimpDisplayShell diff --git a/app/display/gimpdisplayshell-transform.h b/app/display/gimpdisplayshell-transform.h index ead1cdbb83..f3652361f3 100644 --- a/app/display/gimpdisplayshell-transform.h +++ b/app/display/gimpdisplayshell-transform.h @@ -19,6 +19,105 @@ #define __GIMP_DISPLAY_SHELL_TRANSFORM_H__ +/* zoom: functions to transform from image space to unrotated display + * space and back, taking into account scroll offset and scale + */ + +void gimp_display_shell_zoom_coords (const GimpDisplayShell *shell, + const GimpCoords *image_coords, + GimpCoords *display_coords); +void gimp_display_shell_unzoom_coords (const GimpDisplayShell *shell, + const GimpCoords *display_coords, + GimpCoords *image_coords); + +void gimp_display_shell_zoom_xy (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gint *nx, + gint *ny); +void gimp_display_shell_unzoom_xy (const GimpDisplayShell *shell, + gint x, + gint y, + gint *nx, + gint *ny, + gboolean round); + +void gimp_display_shell_zoom_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny); +void gimp_display_shell_unzoom_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny); + +void gimp_display_shell_zoom_segments (const GimpDisplayShell *shell, + const GimpBoundSeg *src_segs, + GimpSegment *dest_segs, + gint n_segs, + gdouble offset_x, + gdouble offset_y); + + +/* rotate: functions to transform from unrotated but zoomed display + * space to rotated display space and back + */ + +void gimp_display_shell_rotate_coords (const GimpDisplayShell *shell, + const GimpCoords *image_coords, + GimpCoords *display_coords); +void gimp_display_shell_unrotate_coords (const GimpDisplayShell *shell, + const GimpCoords *display_coords, + GimpCoords *image_coords); + +void gimp_display_shell_rotate_xy (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gint *nx, + gint *ny); +void gimp_display_shell_unrotate_xy (const GimpDisplayShell *shell, + gint x, + gint y, + gint *nx, + gint *ny); + +void gimp_display_shell_rotate_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny); +void gimp_display_shell_unrotate_xy_f (const GimpDisplayShell *shell, + gdouble x, + gdouble y, + gdouble *nx, + gdouble *ny); + +void gimp_display_shell_rotate_bounds (GimpDisplayShell *shell, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gdouble *nx1, + gdouble *ny1, + gdouble *nx2, + gdouble *ny2); +void gimp_display_shell_unrotate_bounds (GimpDisplayShell *shell, + gdouble x1, + gdouble y1, + gdouble x2, + gdouble y2, + gdouble *nx1, + gdouble *ny1, + gdouble *nx2, + gdouble *ny2); + + +/* transform: functions to transform from image space to rotated display + * space and back, taking into account scroll offset, scale, and rotation + */ + void gimp_display_shell_transform_coords (const GimpDisplayShell *shell, const GimpCoords *image_coords, GimpCoords *display_coords); @@ -68,13 +167,6 @@ void gimp_display_shell_untransform_bounds (const GimpDisplayShell *shell, gdouble *nx2, gdouble *ny2); -void gimp_display_shell_transform_segments (const GimpDisplayShell *shell, - const GimpBoundSeg *src_segs, - GimpSegment *dest_segs, - gint n_segs, - gdouble offset_x, - gdouble offset_y); - void gimp_display_shell_untransform_viewport (const GimpDisplayShell *shell, gint *x, gint *y, diff --git a/app/tools/gimpdrawtool.c b/app/tools/gimpdrawtool.c index 61828120ee..48b66148e9 100644 --- a/app/tools/gimpdrawtool.c +++ b/app/tools/gimpdrawtool.c @@ -1009,20 +1009,12 @@ gimp_draw_tool_on_handle (GimpDrawTool *draw_tool, shell = gimp_display_get_shell (display); - gimp_display_shell_transform_xy_f (shell, - x, y, - &tx, &ty); - gimp_display_shell_transform_xy_f (shell, - handle_x, handle_y, - &handle_tx, &handle_ty); - - if (shell->rotate_untransform) - { - cairo_matrix_transform_point (shell->rotate_untransform, - &tx, &ty); - cairo_matrix_transform_point (shell->rotate_untransform, - &handle_tx, &handle_ty); - } + gimp_display_shell_zoom_xy_f (shell, + x, y, + &tx, &ty); + gimp_display_shell_zoom_xy_f (shell, + handle_x, handle_y, + &handle_tx, &handle_ty); switch (type) {