static void gimp_perspective_clone_init (GimpPerspectiveClone *clone) { clone->src_x_fv = 0.0; /* source coords in front_view perspective */ clone->src_y_fv = 0.0; clone->dest_x_fv = 0.0; /* destination coords in front_view perspective */ clone->dest_y_fv = 0.0; gimp_matrix3_identity (&clone->transform); gimp_matrix3_identity (&clone->transform_inv); }
static void gimp_vectors_rotate (GimpItem *item, GimpContext *context, GimpRotationType rotate_type, gdouble center_x, gdouble center_y, gboolean clip_result) { GimpVectors *vectors = GIMP_VECTORS (item); GList *list; GimpMatrix3 matrix; gimp_matrix3_identity (&matrix); gimp_transform_matrix_rotate (&matrix, rotate_type, center_x, center_y); gimp_vectors_freeze (vectors); gimp_image_undo_push_vectors_mod (gimp_item_get_image (item), _("Rotate Path"), vectors); for (list = vectors->strokes; list; list = g_list_next (list)) { GimpStroke *stroke = list->data; gimp_stroke_transform (stroke, &matrix); } gimp_vectors_thaw (vectors); }
void gimp_transform_matrix_scale (GimpMatrix3 *matrix, gint x, gint y, gint width, gint height, gdouble t_x, gdouble t_y, gdouble t_width, gdouble t_height) { gdouble scale_x = 1.0; gdouble scale_y = 1.0; g_return_if_fail (matrix != NULL); if (width > 0) scale_x = t_width / (gdouble) width; if (height > 0) scale_y = t_height / (gdouble) height; gimp_matrix3_identity (matrix); gimp_matrix3_translate (matrix, -x, -y); gimp_matrix3_scale (matrix, scale_x, scale_y); gimp_matrix3_translate (matrix, t_x, t_y); }
void gimp_transform_matrix_shear (GimpMatrix3 *matrix, gint x, gint y, gint width, gint height, GimpOrientationType orientation, gdouble amount) { gdouble center_x; gdouble center_y; g_return_if_fail (matrix != NULL); if (width == 0) width = 1; if (height == 0) height = 1; center_x = (gdouble) x + (gdouble) width / 2.0; center_y = (gdouble) y + (gdouble) height / 2.0; gimp_matrix3_identity (matrix); gimp_matrix3_translate (matrix, -center_x, -center_y); if (orientation == GIMP_ORIENTATION_HORIZONTAL) gimp_matrix3_xshear (matrix, amount / height); else gimp_matrix3_yshear (matrix, amount / width); gimp_matrix3_translate (matrix, +center_x, +center_y); }
static void gimp_perspective_clone_tool_recalc_matrix (GimpPerspectiveCloneTool *clone_tool, GimpToolWidget *widget) { gimp_matrix3_identity (&clone_tool->transform); gimp_transform_matrix_perspective (&clone_tool->transform, clone_tool->x1, clone_tool->y1, clone_tool->x2 - clone_tool->x1, clone_tool->y2 - clone_tool->y1, clone_tool->trans_info[X0], clone_tool->trans_info[Y0], clone_tool->trans_info[X1], clone_tool->trans_info[Y1], clone_tool->trans_info[X2], clone_tool->trans_info[Y2], clone_tool->trans_info[X3], clone_tool->trans_info[Y3]); if (widget) g_object_set (widget, "transform", &clone_tool->transform, "x1", (gdouble) clone_tool->x1, "y1", (gdouble) clone_tool->y1, "x2", (gdouble) clone_tool->x2, "y2", (gdouble) clone_tool->y2, "pivot-x", clone_tool->trans_info[PIVOT_X], "pivot-y", clone_tool->trans_info[PIVOT_Y], NULL); }
static void gimp_shear_tool_recalc_matrix (GimpTransformTool *tr_tool) { gdouble amount; if (tr_tool->trans_info[XSHEAR] == 0.0 && tr_tool->trans_info[YSHEAR] == 0.0) { tr_tool->trans_info[HORZ_OR_VERT] = GIMP_ORIENTATION_UNKNOWN; } if (tr_tool->trans_info[HORZ_OR_VERT] == GIMP_ORIENTATION_HORIZONTAL) amount = tr_tool->trans_info[XSHEAR]; else amount = tr_tool->trans_info[YSHEAR]; gimp_matrix3_identity (&tr_tool->transform); gimp_transform_matrix_shear (&tr_tool->transform, tr_tool->x1, tr_tool->y1, tr_tool->x2 - tr_tool->x1, tr_tool->y2 - tr_tool->y1, tr_tool->trans_info[HORZ_OR_VERT], amount); }
static void gimp_perspective_clone_tool_init (GimpPerspectiveCloneTool *clone_tool) { GimpTool *tool = GIMP_TOOL (clone_tool); gimp_tool_control_set_action_object_2 (tool->control, "context/context-pattern-select-set"); gimp_matrix3_identity (&clone_tool->transform); }
static void gimp_rotate_tool_recalc_matrix (GimpTransformTool *tr_tool) { tr_tool->px = tr_tool->trans_info[PIVOT_X]; tr_tool->py = tr_tool->trans_info[PIVOT_Y]; gimp_matrix3_identity (&tr_tool->transform); gimp_transform_matrix_rotate_center (&tr_tool->transform, tr_tool->px, tr_tool->py, tr_tool->trans_info[ANGLE]); }
static void gimp_scale_tool_recalc_matrix (GimpTransformTool *tr_tool) { gimp_matrix3_identity (&tr_tool->transform); gimp_transform_matrix_scale (&tr_tool->transform, tr_tool->x1, tr_tool->y1, tr_tool->x2 - tr_tool->x1, tr_tool->y2 - tr_tool->y1, tr_tool->trans_info[X0], tr_tool->trans_info[Y0], tr_tool->trans_info[X1] - tr_tool->trans_info[X0], tr_tool->trans_info[Y1] - tr_tool->trans_info[Y0]); }
static void gimp_perspective_clone_get_matrix (GimpPerspectiveClone *clone, GimpMatrix3 *matrix) { GimpMatrix3 temp; gimp_matrix3_identity (&temp); gimp_matrix3_translate (&temp, clone->dest_x_fv - clone->src_x_fv, clone->dest_y_fv - clone->src_y_fv); *matrix = clone->transform_inv; gimp_matrix3_mult (&temp, matrix); gimp_matrix3_mult (&clone->transform, matrix); }
static void gimp_perspective_tool_recalc_matrix (GimpTransformTool *tr_tool) { gimp_matrix3_identity (&tr_tool->transform); gimp_transform_matrix_perspective (&tr_tool->transform, tr_tool->x1, tr_tool->y1, tr_tool->x2 - tr_tool->x1, tr_tool->y2 - tr_tool->y1, tr_tool->trans_info[X0], tr_tool->trans_info[Y0], tr_tool->trans_info[X1], tr_tool->trans_info[Y1], tr_tool->trans_info[X2], tr_tool->trans_info[Y2], tr_tool->trans_info[X3], tr_tool->trans_info[Y3]); }
static void gimp_mandala_update_strokes (GimpSymmetry *sym, GimpDrawable *drawable, GimpCoords *origin) { GimpMandala *mandala = GIMP_MANDALA (sym); GimpCoords *coords; GimpMatrix3 matrix; gint i; g_list_free_full (sym->strokes, g_free); sym->strokes = NULL; coords = g_memdup (sym->origin, sizeof (GimpCoords)); sym->strokes = g_list_prepend (sym->strokes, coords); for (i = 1; i < mandala->size; i++) { gdouble new_x, new_y; coords = g_memdup (sym->origin, sizeof (GimpCoords)); gimp_matrix3_identity (&matrix); gimp_matrix3_translate (&matrix, - mandala->center_x, - mandala->center_y); gimp_matrix3_rotate (&matrix, - i * 2.0 * G_PI / (gdouble) mandala->size); gimp_matrix3_translate (&matrix, mandala->center_x, mandala->center_y); gimp_matrix3_transform_point (&matrix, coords->x, coords->y, &new_x, &new_y); coords->x = new_x; coords->y = new_y; sym->strokes = g_list_prepend (sym->strokes, coords); } sym->strokes = g_list_reverse (sym->strokes); g_signal_emit_by_name (sym, "strokes-updated", sym->image); }
void gimp_transform_matrix_flip_free (GimpMatrix3 *matrix, gdouble x1, gdouble y1, gdouble x2, gdouble y2) { gdouble angle; g_return_if_fail (matrix != NULL); angle = atan2 (y2 - y1, x2 - x1); gimp_matrix3_identity (matrix); gimp_matrix3_translate (matrix, -x1, -y1); gimp_matrix3_rotate (matrix, -angle); gimp_matrix3_scale (matrix, 1.0, -1.0); gimp_matrix3_rotate (matrix, angle); gimp_matrix3_translate (matrix, x1, y1); }
static void gimp_perspective_clone_tool_recalc_matrix (GimpPerspectiveCloneTool *clone_tool) { gimp_matrix3_identity (&clone_tool->transform); gimp_transform_matrix_perspective (&clone_tool->transform, clone_tool->x1, clone_tool->y1, clone_tool->x2 - clone_tool->x1, clone_tool->y2 - clone_tool->y1, clone_tool->trans_info[X0], clone_tool->trans_info[Y0], clone_tool->trans_info[X1], clone_tool->trans_info[Y1], clone_tool->trans_info[X2], clone_tool->trans_info[Y2], clone_tool->trans_info[X3], clone_tool->trans_info[Y3]); gimp_perspective_clone_tool_transform_bounding_box (clone_tool); }
static GimpValueArray * shear_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GimpValueArray *args, GError **error) { gboolean success = TRUE; GimpValueArray *return_vals; GimpDrawable *drawable; gboolean interpolation; gint32 shear_type; gdouble magnitude; drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp); interpolation = g_value_get_boolean (gimp_value_array_index (args, 1)); shear_type = g_value_get_enum (gimp_value_array_index (args, 2)); magnitude = g_value_get_double (gimp_value_array_index (args, 3)); if (success) { gint x, y, width, height; success = gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, TRUE, error); if (success && gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) { GimpMatrix3 matrix; GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE; gint off_x, off_y; gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); x += off_x; y += off_y; /* Assemble the transformation matrix */ gimp_matrix3_identity (&matrix); gimp_transform_matrix_shear (&matrix, x, y, width, height, shear_type, magnitude); if (interpolation) interpolation_type = gimp->config->interpolation_type; if (progress) gimp_progress_start (progress, _("Shearing"), FALSE); if (! gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) && ! gimp_channel_is_empty (gimp_image_get_mask (gimp_item_get_image (GIMP_ITEM (drawable))))) { if (! gimp_drawable_transform_affine (drawable, context, &matrix, GIMP_TRANSFORM_FORWARD, interpolation_type, 3, FALSE, progress)) { success = FALSE; } } else { gimp_item_transform (GIMP_ITEM (drawable), context, &matrix, GIMP_TRANSFORM_FORWARD, interpolation, 3, FALSE, progress); } if (progress) gimp_progress_end (progress); } } return_vals = gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); if (success) gimp_value_set_drawable (gimp_value_array_index (return_vals, 1), drawable); return return_vals; }
GeglBuffer * gimp_drawable_transform_buffer_affine (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, const GimpMatrix3 *matrix, GimpTransformDirection direction, GimpInterpolationType interpolation_type, gint recursion_level, GimpTransformResize clip_result, gint *new_offset_x, gint *new_offset_y, GimpProgress *progress) { GeglBuffer *new_buffer; GimpMatrix3 m; GimpMatrix3 inv; gint u1, v1, u2, v2; /* source bounding box */ gint x1, y1, x2, y2; /* target bounding box */ GeglNode *affine; GimpMatrix3 gegl_matrix; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); g_return_val_if_fail (matrix != NULL, NULL); g_return_val_if_fail (new_offset_x != NULL, NULL); g_return_val_if_fail (new_offset_y != NULL, NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); m = *matrix; inv = *matrix; if (direction == GIMP_TRANSFORM_BACKWARD) { /* keep the original matrix here, so we dont need to recalculate * the inverse later */ gimp_matrix3_invert (&inv); } else { /* Find the inverse of the transformation matrix */ gimp_matrix3_invert (&m); } u1 = orig_offset_x; v1 = orig_offset_y; u2 = u1 + gegl_buffer_get_width (orig_buffer); v2 = v1 + gegl_buffer_get_height (orig_buffer); /* Always clip unfloated buffers since they must keep their size */ if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL && ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer))) clip_result = GIMP_TRANSFORM_RESIZE_CLIP; /* Find the bounding coordinates of target */ gimp_transform_resize_boundary (&inv, clip_result, u1, v1, u2, v2, &x1, &y1, &x2, &y2); /* Get the new temporary buffer for the transformed result */ new_buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), gegl_buffer_get_format (orig_buffer)); gimp_matrix3_identity (&gegl_matrix); gimp_matrix3_translate (&gegl_matrix, u1, v1); gimp_matrix3_mult (&inv, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1, -y1); affine = gegl_node_new_child (NULL, "operation", "gegl:transform", "filter", gimp_interpolation_to_gegl_filter (interpolation_type), "hard-edges", TRUE, NULL); gimp_gegl_node_set_matrix (affine, &gegl_matrix); gimp_apply_operation (orig_buffer, progress, NULL, affine, new_buffer, NULL); g_object_unref (affine); *new_offset_x = x1; *new_offset_y = y1; return new_buffer; }
static GeglBuffer * gimp_perspective_clone_get_source (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, GimpPickable *src_pickable, gint src_offset_x, gint src_offset_y, GeglBuffer *paint_buffer, gint paint_buffer_x, gint paint_buffer_y, gint *paint_area_offset_x, gint *paint_area_offset_y, gint *paint_area_width, gint *paint_area_height, GeglRectangle *src_rect) { GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (source_core); GimpCloneOptions *clone_options = GIMP_CLONE_OPTIONS (paint_options); GeglBuffer *src_buffer; GeglBuffer *dest_buffer; const Babl *src_format_alpha; gint x1d, y1d, x2d, y2d; gdouble x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s; gint xmin, ymin, xmax, ymax; GimpMatrix3 matrix; GimpMatrix3 gegl_matrix; src_buffer = gimp_pickable_get_buffer (src_pickable); src_format_alpha = gimp_pickable_get_format_with_alpha (src_pickable); /* Destination coordinates that will be painted */ x1d = paint_buffer_x; y1d = paint_buffer_y; x2d = paint_buffer_x + gegl_buffer_get_width (paint_buffer); y2d = paint_buffer_y + gegl_buffer_get_height (paint_buffer); /* Boundary box for source pixels to copy: Convert all the vertex of * the box to paint in destination area to its correspondent in * source area bearing in mind perspective */ gimp_perspective_clone_get_source_point (clone, x1d, y1d, &x1s, &y1s); gimp_perspective_clone_get_source_point (clone, x1d, y2d, &x2s, &y2s); gimp_perspective_clone_get_source_point (clone, x2d, y1d, &x3s, &y3s); gimp_perspective_clone_get_source_point (clone, x2d, y2d, &x4s, &y4s); xmin = floor (MIN4 (x1s, x2s, x3s, x4s)); ymin = floor (MIN4 (y1s, y2s, y3s, y4s)); xmax = ceil (MAX4 (x1s, x2s, x3s, x4s)); ymax = ceil (MAX4 (y1s, y2s, y3s, y4s)); switch (clone_options->clone_type) { case GIMP_IMAGE_CLONE: if (! gimp_rectangle_intersect (xmin, ymin, xmax - xmin, ymax - ymin, 0, 0, gegl_buffer_get_width (src_buffer), gegl_buffer_get_height (src_buffer), NULL, NULL, NULL, NULL)) { /* if the source area is completely out of the image */ return NULL; } break; case GIMP_PATTERN_CLONE: gegl_node_set (clone->crop, "x", (gdouble) xmin, "y", (gdouble) ymin, "width", (gdouble) xmax - xmin, "height", (gdouble) ymax - ymin, NULL); break; } dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d), src_format_alpha); gimp_perspective_clone_get_matrix (clone, &matrix); gimp_matrix3_identity (&gegl_matrix); gimp_matrix3_mult (&matrix, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1d, -y1d); gimp_gegl_node_set_matrix (clone->transform_node, &gegl_matrix); gegl_node_set (clone->dest_node, "buffer", dest_buffer, NULL); gegl_node_blit (clone->dest_node, 1.0, GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d), NULL, NULL, 0, GEGL_BLIT_DEFAULT); *src_rect = *GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d); return dest_buffer; }
static GimpValueArray * transform_2d_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GimpValueArray *args, GError **error) { gboolean success = TRUE; GimpValueArray *return_vals; GimpDrawable *drawable; gboolean interpolation; gdouble source_x; gdouble source_y; gdouble scale_x; gdouble scale_y; gdouble angle; gdouble dest_x; gdouble dest_y; drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp); interpolation = g_value_get_boolean (gimp_value_array_index (args, 1)); source_x = g_value_get_double (gimp_value_array_index (args, 2)); source_y = g_value_get_double (gimp_value_array_index (args, 3)); scale_x = g_value_get_double (gimp_value_array_index (args, 4)); scale_y = g_value_get_double (gimp_value_array_index (args, 5)); angle = g_value_get_double (gimp_value_array_index (args, 6)); dest_x = g_value_get_double (gimp_value_array_index (args, 7)); dest_y = g_value_get_double (gimp_value_array_index (args, 8)); if (success) { gint x, y, width, height; success = gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, TRUE, error); if (success && gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) { GimpMatrix3 matrix; GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE; /* Assemble the transformation matrix */ gimp_matrix3_identity (&matrix); gimp_matrix3_translate (&matrix, -source_x, -source_y); gimp_matrix3_scale (&matrix, scale_x, scale_y); gimp_matrix3_rotate (&matrix, angle); gimp_matrix3_translate (&matrix, dest_x, dest_y); if (interpolation) interpolation_type = gimp->config->interpolation_type; if (progress) gimp_progress_start (progress, _("2D Transform"), FALSE); if (! gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) && ! gimp_channel_is_empty (gimp_image_get_mask (gimp_item_get_image (GIMP_ITEM (drawable))))) { if (! gimp_drawable_transform_affine (drawable, context, &matrix, GIMP_TRANSFORM_FORWARD, interpolation_type, 3, FALSE, progress)) { success = FALSE; } } else { gimp_item_transform (GIMP_ITEM (drawable), context, &matrix, GIMP_TRANSFORM_FORWARD, interpolation, 3, FALSE, progress); } if (progress) gimp_progress_end (progress); } } return_vals = gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); if (success) gimp_value_set_drawable (gimp_value_array_index (return_vals, 1), drawable); return return_vals; }
GeglBuffer * gimp_drawable_transform_buffer_affine (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, const GimpMatrix3 *matrix, GimpTransformDirection direction, GimpInterpolationType interpolation_type, GimpTransformResize clip_result, GimpColorProfile **buffer_profile, gint *new_offset_x, gint *new_offset_y, GimpProgress *progress) { GeglBuffer *new_buffer; GimpMatrix3 m; gint u1, v1, u2, v2; /* source bounding box */ gint x1, y1, x2, y2; /* target bounding box */ GimpMatrix3 gegl_matrix; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); g_return_val_if_fail (matrix != NULL, NULL); g_return_val_if_fail (buffer_profile != NULL, NULL); g_return_val_if_fail (new_offset_x != NULL, NULL); g_return_val_if_fail (new_offset_y != NULL, NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); *buffer_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable)); m = *matrix; if (direction == GIMP_TRANSFORM_BACKWARD) { /* Find the inverse of the transformation matrix */ gimp_matrix3_invert (&m); } u1 = orig_offset_x; v1 = orig_offset_y; u2 = u1 + gegl_buffer_get_width (orig_buffer); v2 = v1 + gegl_buffer_get_height (orig_buffer); /* Don't modify the clipping mode of layer masks here, so that, * when transformed together with their layer, they match the * layer's clipping mode. */ if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL) { clip_result = gimp_drawable_transform_get_effective_clip (drawable, orig_buffer, clip_result); } /* Find the bounding coordinates of target */ gimp_transform_resize_boundary (&m, clip_result, u1, v1, u2, v2, &x1, &y1, &x2, &y2); /* Get the new temporary buffer for the transformed result */ new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), gegl_buffer_get_format (orig_buffer)); gimp_matrix3_identity (&gegl_matrix); gimp_matrix3_translate (&gegl_matrix, u1, v1); gimp_matrix3_mult (&m, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1, -y1); gimp_gegl_apply_transform (orig_buffer, progress, NULL, new_buffer, interpolation_type, &gegl_matrix); *new_offset_x = x1; *new_offset_y = y1; return new_buffer; }