static gboolean gimp_operation_cage_coef_calc_process (GeglOperation *operation, GeglBuffer *output, const GeglRectangle *roi) { GimpOperationCageCoefCalc *occc = GIMP_OPERATION_CAGE_COEF_CALC (operation); GimpCageConfig *config = GIMP_CAGE_CONFIG (occc->config); Babl *format = babl_format_n (babl_type ("float"), 2 * gimp_cage_config_get_n_points (config)); GeglBufferIterator *it; guint n_cage_vertices; GimpCagePoint *current, *last; if (! config) return FALSE; n_cage_vertices = gimp_cage_config_get_n_points (config); it = gegl_buffer_iterator_new (output, roi, format, GEGL_BUFFER_READWRITE); while (gegl_buffer_iterator_next (it)) { /* iterate inside the roi */ gint n_pixels = it->length; gint x = it->roi->x; /* initial x */ gint y = it->roi->y; /* and y coordinates */ gint j; gfloat *coef = it->data[0]; while(n_pixels--) { if (gimp_cage_config_point_inside(config, x, y)) { last = &(g_array_index (config->cage_points, GimpCagePoint, 0)); for( j = 0; j < n_cage_vertices; j++) { GimpVector2 v1,v2,a,b,p; gdouble BA,SRT,L0,L1,A0,A1,A10,L10, Q,S,R, absa; current = &(g_array_index (config->cage_points, GimpCagePoint, (j+1) % n_cage_vertices)); v1 = last->src_point; v2 = current->src_point; p.x = x; p.y = y; a.x = v2.x - v1.x; a.y = v2.y - v1.y; absa = gimp_vector2_length (&a); b.x = v1.x - x; b.y = v1.y - y; Q = a.x * a.x + a.y * a.y; S = b.x * b.x + b.y * b.y; R = 2.0 * (a.x * b.x + a.y * b.y); BA = b.x * a.y - b.y * a.x; SRT = sqrt(4.0 * S * Q - R * R); L0 = log(S); L1 = log(S + Q + R); A0 = atan2(R, SRT) / SRT; A1 = atan2(2.0 * Q + R, SRT) / SRT; A10 = A1 - A0; L10 = L1 - L0; /* edge coef */ coef[j + n_cage_vertices] = (-absa / (4.0 * G_PI)) * ((4.0*S-(R*R)/Q) * A10 + (R / (2.0 * Q)) * L10 + L1 - 2.0); if (isnan(coef[j + n_cage_vertices])) { coef[j + n_cage_vertices] = 0.0; } /* vertice coef */ if (!gimp_operation_cage_coef_calc_is_on_straight (&v1, &v2, &p)) { coef[j] += (BA / (2.0 * G_PI)) * (L10 /(2.0*Q) - A10 * (2.0 + R / Q)); coef[(j+1)%n_cage_vertices] -= (BA / (2.0 * G_PI)) * (L10 / (2.0 * Q) - A10 * (R / Q)); } last = current; } } coef += 2 * n_cage_vertices; /* update x and y coordinates */ x++; if (x >= (it->roi->x + it->roi->width)) { x = it->roi->x; y++; } } } return TRUE; }
static gboolean gimp_operation_cage_transform_process (GeglOperation *operation, GeglBuffer *in_buf, GeglBuffer *aux_buf, GeglBuffer *out_buf, const GeglRectangle *roi, gint level) { GimpOperationCageTransform *oct = GIMP_OPERATION_CAGE_TRANSFORM (operation); GimpCageConfig *config = GIMP_CAGE_CONFIG (oct->config); GeglRectangle cage_bb; gfloat *coords; gfloat *coef; const Babl *format_coef; GimpVector2 plain_color; GeglBufferIterator *it; gint x, y; gboolean output_set; GimpCagePoint *point; guint n_cage_vertices; /* pre-fill the out buffer with no-displacement coordinate */ it = gegl_buffer_iterator_new (out_buf, roi, 0, NULL, GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); cage_bb = gimp_cage_config_get_bounding_box (config); point = &(g_array_index (config->cage_points, GimpCagePoint, 0)); plain_color.x = (gint) point->src_point.x; plain_color.y = (gint) point->src_point.y; n_cage_vertices = gimp_cage_config_get_n_points (config); while (gegl_buffer_iterator_next (it)) { /* iterate inside the roi */ gint n_pixels = it->length; gfloat *output = it->data[0]; x = it->roi->x; /* initial x */ y = it->roi->y; /* and y coordinates */ while (n_pixels--) { output_set = FALSE; if (oct->fill_plain_color) { if (x > cage_bb.x && y > cage_bb.y && x < cage_bb.x + cage_bb.width && y < cage_bb.y + cage_bb.height) { if (gimp_cage_config_point_inside (config, x, y)) { output[0] = plain_color.x; output[1] = plain_color.y; output_set = TRUE; } } } if (!output_set) { output[0] = x; output[1] = y; } output += 2; /* update x and y coordinates */ x++; if (x >= (it->roi->x + it->roi->width)) { x = it->roi->x; y++; } } } oct->progress = 0.0; g_object_notify (G_OBJECT (oct), "progress"); /* pre-allocate memory outside of the loop */ coords = g_slice_alloc (2 * sizeof (gfloat)); coef = g_malloc (n_cage_vertices * 2 * sizeof (gfloat)); format_coef = babl_format_n (babl_type ("float"), 2 * n_cage_vertices); /* compute, reverse and interpolate the transformation */ for (y = cage_bb.y; y < cage_bb.y + cage_bb.height - 1; y++) { GimpVector2 p1_d, p2_d, p3_d, p4_d; GimpVector2 p1_s, p2_s, p3_s, p4_s; p1_s.y = y; p2_s.y = y+1; p3_s.y = y+1; p3_s.x = cage_bb.x; p4_s.y = y; p4_s.x = cage_bb.x; p3_d = gimp_cage_transform_compute_destination (config, coef, format_coef, aux_buf, p3_s); p4_d = gimp_cage_transform_compute_destination (config, coef, format_coef, aux_buf, p4_s); for (x = cage_bb.x; x < cage_bb.x + cage_bb.width - 1; x++) { p1_s = p4_s; p2_s = p3_s; p3_s.x = x+1; p4_s.x = x+1; p1_d = p4_d; p2_d = p3_d; p3_d = gimp_cage_transform_compute_destination (config, coef, format_coef, aux_buf, p3_s); p4_d = gimp_cage_transform_compute_destination (config, coef, format_coef, aux_buf, p4_s); if (gimp_cage_config_point_inside (config, x, y)) { gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, out_buf, roi, p1_s, p1_d, p2_s, p2_d, p3_s, p3_d, 0, coords); gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, out_buf, roi, p1_s, p1_d, p3_s, p3_d, p4_s, p4_d, 0, coords); } } if ((y - cage_bb.y) % 20 == 0) { gdouble fraction = ((gdouble) (y - cage_bb.y) / (gdouble) (cage_bb.height)); /* 0.0 and 1.0 indicate progress start/end, so avoid them */ if (fraction > 0.0 && fraction < 1.0) { oct->progress = fraction; g_object_notify (G_OBJECT (oct), "progress"); } } } g_free (coef); g_slice_free1 (2 * sizeof (gfloat), coords); oct->progress = 1.0; g_object_notify (G_OBJECT (oct), "progress"); return TRUE; }