app: allow canceling line-art computation
Line-art computation can take a long time, and it's therefore
desirable for it to be interruptable. While we do cancel the line-
art async when its result is no longer needed, most parts of the
computation don't respond to the cancelation request, leaving the
async operation running in the background, blocking subsequent
async operations.
Implement cancelation support of line-art computation, by passing
down the async object to the various functions, and periodically
checking for its cancelation at various points. When the async is
canceled, we quickly abort the operation.
Even though cancelation now happens relatively quickly, some parts
of the computation are still uninterruptable and may incur some
latency, so we avoid waiting for the async opration to be aborted
after cancelation, as we did before.
(cherry picked from commit d8e69d66bc
)
This commit is contained in:
@ -193,20 +193,25 @@ static GeglBuffer * gimp_line_art_close (GeglBuffer
|
||||
gint created_regions_significant_area,
|
||||
gint created_regions_minimum_area,
|
||||
gboolean small_segments_from_spline_sources,
|
||||
gfloat **lineart_distmap);
|
||||
gfloat **lineart_distmap,
|
||||
GimpAsync *async);
|
||||
|
||||
static void gimp_lineart_denoise (GeglBuffer *buffer,
|
||||
int size);
|
||||
int size,
|
||||
GimpAsync *async);
|
||||
static void gimp_lineart_compute_normals_curvatures (GeglBuffer *mask,
|
||||
gfloat *normals,
|
||||
gfloat *curvatures,
|
||||
gfloat *smoothed_curvatures,
|
||||
int normal_estimate_mask_size);
|
||||
static gfloat * gimp_lineart_get_smooth_curvatures (GArray *edgelset);
|
||||
int normal_estimate_mask_size,
|
||||
GimpAsync *async);
|
||||
static gfloat * gimp_lineart_get_smooth_curvatures (GArray *edgelset,
|
||||
GimpAsync *async);
|
||||
static GArray * gimp_lineart_curvature_extremums (gfloat *curvatures,
|
||||
gfloat *smoothed_curvatures,
|
||||
gint curvatures_width,
|
||||
gint curvatures_height);
|
||||
gint curvatures_height,
|
||||
GimpAsync *async);
|
||||
static gint gimp_spline_candidate_cmp (const SplineCandidate *a,
|
||||
const SplineCandidate *b,
|
||||
gpointer user_data);
|
||||
@ -214,7 +219,8 @@ static GList * gimp_lineart_find_spline_candidates (GArray
|
||||
gfloat *normals,
|
||||
gint width,
|
||||
gint distance_threshold,
|
||||
gfloat max_angle_deg);
|
||||
gfloat max_angle_deg,
|
||||
GimpAsync *async);
|
||||
|
||||
static GArray * gimp_lineart_discrete_spline (Pixel p0,
|
||||
GimpVector2 n0,
|
||||
@ -232,7 +238,8 @@ static GArray * gimp_lineart_line_segment_until_hit (const GeglBuffe
|
||||
Pixel start,
|
||||
GimpVector2 direction,
|
||||
int size);
|
||||
static gfloat * gimp_lineart_estimate_strokes_radii (GeglBuffer *mask);
|
||||
static gfloat * gimp_lineart_estimate_strokes_radii (GeglBuffer *mask,
|
||||
GimpAsync *async);
|
||||
static void gimp_line_art_simple_fill (GeglBuffer *buffer,
|
||||
gint x,
|
||||
gint y);
|
||||
@ -271,7 +278,8 @@ static glong gimp_edgel_region_area (const GeglBuffer *mask,
|
||||
|
||||
/* Edgel set */
|
||||
|
||||
static GArray * gimp_edgelset_new (GeglBuffer *buffer);
|
||||
static GArray * gimp_edgelset_new (GeglBuffer *buffer,
|
||||
GimpAsync *async);
|
||||
static void gimp_edgelset_add (GArray *set,
|
||||
int x,
|
||||
int y,
|
||||
@ -279,12 +287,15 @@ static void gimp_edgelset_add (GArray *set,
|
||||
GHashTable *edgel2index);
|
||||
static void gimp_edgelset_init_normals (GArray *set);
|
||||
static void gimp_edgelset_smooth_normals (GArray *set,
|
||||
int mask_size);
|
||||
static void gimp_edgelset_compute_curvature (GArray *set);
|
||||
int mask_size,
|
||||
GimpAsync *async);
|
||||
static void gimp_edgelset_compute_curvature (GArray *set,
|
||||
GimpAsync *async);
|
||||
|
||||
static void gimp_edgelset_build_graph (GArray *set,
|
||||
GeglBuffer *buffer,
|
||||
GHashTable *edgel2index);
|
||||
GHashTable *edgel2index,
|
||||
GimpAsync *async);
|
||||
static void gimp_edgelset_next8 (const GeglBuffer *buffer,
|
||||
Edgel *it,
|
||||
Edgel *n);
|
||||
@ -563,7 +574,7 @@ gimp_line_art_compute (GimpLineArt *line_art)
|
||||
if (line_art->priv->async)
|
||||
{
|
||||
/* we cancel the async, but don't wait for it to finish, since
|
||||
* it can't actually be interrupted. instead gimp_line_art_compute_cb()
|
||||
* it might take a while to respond. instead gimp_line_art_compute_cb()
|
||||
* bails if the async has been canceled, to avoid accessing the line art.
|
||||
*/
|
||||
g_signal_emit (line_art, gimp_line_art_signals[COMPUTING_END], 0);
|
||||
@ -655,8 +666,8 @@ static void
|
||||
gimp_line_art_prepare_async_func (GimpAsync *async,
|
||||
LineArtData *data)
|
||||
{
|
||||
GeglBuffer *closed;
|
||||
gfloat *distmap;
|
||||
GeglBuffer *closed = NULL;
|
||||
gfloat *distmap = NULL;
|
||||
gboolean has_alpha;
|
||||
gboolean select_transparent = FALSE;
|
||||
|
||||
@ -738,13 +749,17 @@ gimp_line_art_prepare_async_func (GimpAsync *async,
|
||||
100,
|
||||
/*small_segments_from_spline_sources,*/
|
||||
TRUE,
|
||||
&distmap);
|
||||
&distmap,
|
||||
async);
|
||||
|
||||
GIMP_TIMER_END("close line-art");
|
||||
|
||||
if (! gimp_async_is_stopped (async))
|
||||
{
|
||||
gimp_async_finish_full (async,
|
||||
line_art_result_new (closed, distmap),
|
||||
(GDestroyNotify) line_art_result_free);
|
||||
}
|
||||
|
||||
line_art_data_free (data);
|
||||
}
|
||||
@ -846,6 +861,7 @@ gimp_line_art_input_invalidate_preview (GimpViewable *viewable,
|
||||
* @created_regions_minimum_area:
|
||||
* @small_segments_from_spline_sources:
|
||||
* @closed_distmap: a distance map of the closed line art pixels.
|
||||
* @async: the #GimpAsync associated with the computation
|
||||
*
|
||||
* Creates a binarized version of the strokes of @buffer, detected either
|
||||
* with luminosity (light means background) or alpha values depending on
|
||||
@ -881,12 +897,13 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
gint created_regions_significant_area,
|
||||
gint created_regions_minimum_area,
|
||||
gboolean small_segments_from_spline_sources,
|
||||
gfloat **closed_distmap)
|
||||
gfloat **closed_distmap,
|
||||
GimpAsync *async)
|
||||
{
|
||||
const Babl *gray_format;
|
||||
GeglBufferIterator *gi;
|
||||
GeglBuffer *closed;
|
||||
GeglBuffer *strokes;
|
||||
GeglBuffer *closed = NULL;
|
||||
GeglBuffer *strokes = NULL;
|
||||
guchar max_value = 0;
|
||||
gint width = gegl_buffer_get_width (buffer);
|
||||
gint height = gegl_buffer_get_height (buffer);
|
||||
@ -915,6 +932,15 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
guchar *data = (guchar*) gi->items[0].data;
|
||||
gint k;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gegl_buffer_iterator_stop (gi);
|
||||
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end1;
|
||||
}
|
||||
|
||||
for (k = 0; k < gi->length; k++)
|
||||
{
|
||||
if (*data > max_value)
|
||||
@ -932,6 +958,15 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
guchar *data = (guchar*) gi->items[0].data;
|
||||
gint k;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gegl_buffer_iterator_stop (gi);
|
||||
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end1;
|
||||
}
|
||||
|
||||
for (k = 0; k < gi->length; k++)
|
||||
{
|
||||
if (! select_transparent)
|
||||
@ -947,18 +982,20 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
}
|
||||
|
||||
/* Denoise (remove small connected components) */
|
||||
gimp_lineart_denoise (strokes, minimal_lineart_area);
|
||||
gimp_lineart_denoise (strokes, minimal_lineart_area, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end1;
|
||||
|
||||
closed = strokes;
|
||||
closed = g_object_ref (strokes);
|
||||
|
||||
if (spline_max_length > 0 || segment_max_length > 0)
|
||||
{
|
||||
GArray *keypoints;
|
||||
GHashTable *visited;
|
||||
gfloat *radii;
|
||||
gfloat *normals;
|
||||
gfloat *curvatures;
|
||||
gfloat *smoothed_curvatures;
|
||||
GArray *keypoints = NULL;
|
||||
GHashTable *visited = NULL;
|
||||
gfloat *radii = NULL;
|
||||
gfloat *normals = NULL;
|
||||
gfloat *curvatures = NULL;
|
||||
gfloat *smoothed_curvatures = NULL;
|
||||
gfloat threshold;
|
||||
gfloat clamped_threshold;
|
||||
GList *fill_pixels = NULL;
|
||||
@ -971,14 +1008,27 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
/* Estimate normals & curvature */
|
||||
gimp_lineart_compute_normals_curvatures (strokes, normals, curvatures,
|
||||
smoothed_curvatures,
|
||||
normal_estimate_mask_size);
|
||||
normal_estimate_mask_size,
|
||||
async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end2;
|
||||
|
||||
radii = gimp_lineart_estimate_strokes_radii (strokes);
|
||||
radii = gimp_lineart_estimate_strokes_radii (strokes, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end2;
|
||||
threshold = 1.0f - end_point_rate;
|
||||
clamped_threshold = MAX (0.25f, threshold);
|
||||
for (i = 0; i < width; i++)
|
||||
{
|
||||
gint j;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end2;
|
||||
}
|
||||
|
||||
for (j = 0; j < height; j++)
|
||||
{
|
||||
if (smoothed_curvatures[i + j * width] >= (threshold / MAX (1.0f, radii[i + j * width])) ||
|
||||
@ -988,10 +1038,13 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
curvatures[i + j * width] = 0.0;
|
||||
}
|
||||
}
|
||||
g_free (radii);
|
||||
g_clear_pointer (&radii, g_free);
|
||||
|
||||
keypoints = gimp_lineart_curvature_extremums (curvatures, smoothed_curvatures,
|
||||
width, height);
|
||||
width, height, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end2;
|
||||
|
||||
visited = g_hash_table_new_full ((GHashFunc) visited_hash_fun,
|
||||
(GEqualFunc) visited_equal_fun,
|
||||
(GDestroyNotify) g_free, NULL);
|
||||
@ -1003,16 +1056,31 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
|
||||
candidates = gimp_lineart_find_spline_candidates (keypoints, normals, width,
|
||||
spline_max_length,
|
||||
spline_max_angle);
|
||||
spline_max_angle,
|
||||
async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end3;
|
||||
|
||||
g_object_unref (closed);
|
||||
closed = gegl_buffer_dup (strokes);
|
||||
|
||||
/* Draw splines */
|
||||
while (candidates)
|
||||
{
|
||||
Pixel *p1 = g_new (Pixel, 1);
|
||||
Pixel *p2 = g_new (Pixel, 1);
|
||||
Pixel *p1;
|
||||
Pixel *p2;
|
||||
gboolean inserted = FALSE;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end3;
|
||||
}
|
||||
|
||||
p1 = g_new (Pixel, 1);
|
||||
p2 = g_new (Pixel, 1);
|
||||
|
||||
candidate = (SplineCandidate *) candidates->data;
|
||||
p1->x = candidate->p1.x;
|
||||
p1->y = candidate->p1.y;
|
||||
@ -1078,8 +1146,12 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
end3:
|
||||
g_list_free_full (candidates, g_free);
|
||||
g_object_unref (strokes);
|
||||
g_clear_object (&strokes);
|
||||
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end2;
|
||||
}
|
||||
|
||||
/* Draw straight line segments */
|
||||
@ -1090,9 +1162,17 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
point = (Pixel *) keypoints->data;
|
||||
for (i = 0; i < keypoints->len; i++)
|
||||
{
|
||||
Pixel *p = g_new (Pixel, 1);
|
||||
Pixel *p;
|
||||
gboolean inserted = FALSE;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end2;
|
||||
}
|
||||
|
||||
p = g_new (Pixel, 1);
|
||||
*p = *point;
|
||||
|
||||
if (! g_hash_table_contains (visited, p) ||
|
||||
@ -1134,6 +1214,13 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
{
|
||||
Pixel *p = iter->data;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end2;
|
||||
}
|
||||
|
||||
/* XXX A best approach would be to generalize
|
||||
* gimp_drawable_bucket_fill() to work on any buffer (the code
|
||||
* is already mostly there) rather than reimplementing a naive
|
||||
@ -1144,12 +1231,16 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
gimp_line_art_simple_fill (closed, (gint) p->x, (gint) p->y);
|
||||
}
|
||||
|
||||
end2:
|
||||
g_list_free_full (fill_pixels, g_free);
|
||||
g_free (normals);
|
||||
g_free (curvatures);
|
||||
g_free (smoothed_curvatures);
|
||||
g_array_free (keypoints, TRUE);
|
||||
g_hash_table_destroy (visited);
|
||||
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end1;
|
||||
}
|
||||
|
||||
if (closed_distmap)
|
||||
@ -1179,12 +1270,19 @@ gimp_line_art_close (GeglBuffer *buffer,
|
||||
g_object_unref (graph);
|
||||
}
|
||||
|
||||
end1:
|
||||
g_clear_object (&strokes);
|
||||
|
||||
if (gimp_async_is_stopped (async))
|
||||
g_clear_object (&closed);
|
||||
|
||||
return closed;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_lineart_denoise (GeglBuffer *buffer,
|
||||
int minimum_area)
|
||||
int minimum_area,
|
||||
GimpAsync *async)
|
||||
{
|
||||
/* Keep connected regions with significant area. */
|
||||
GArray *region;
|
||||
@ -1201,6 +1299,13 @@ gimp_lineart_denoise (GeglBuffer *buffer,
|
||||
{
|
||||
guchar has_stroke;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
gegl_buffer_sample (buffer, x, y, NULL, &has_stroke, NULL,
|
||||
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
|
||||
if (has_stroke && ! visited[x + y * width])
|
||||
@ -1220,6 +1325,13 @@ gimp_lineart_denoise (GeglBuffer *buffer,
|
||||
gint p2x;
|
||||
gint p2y;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
p2x = p->x + 1;
|
||||
p2y = p->y;
|
||||
if (p2x >= 0 && p2x < width && p2y >= 0 && p2y < height)
|
||||
@ -1370,6 +1482,8 @@ gimp_lineart_denoise (GeglBuffer *buffer,
|
||||
g_array_remove_range (region, 0, region->len);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
g_array_free (region, TRUE);
|
||||
g_queue_free_full (q, g_free);
|
||||
g_free (visited);
|
||||
@ -1380,22 +1494,41 @@ gimp_lineart_compute_normals_curvatures (GeglBuffer *mask,
|
||||
gfloat *normals,
|
||||
gfloat *curvatures,
|
||||
gfloat *smoothed_curvatures,
|
||||
int normal_estimate_mask_size)
|
||||
int normal_estimate_mask_size,
|
||||
GimpAsync *async)
|
||||
{
|
||||
gfloat *edgels_curvatures;
|
||||
gfloat *edgels_curvatures = NULL;
|
||||
gfloat *smoothed_curvature;
|
||||
GArray *es = gimp_edgelset_new (mask);
|
||||
Edgel **e = (Edgel **) es->data;
|
||||
GArray *es = NULL;
|
||||
Edgel **e;
|
||||
gint width = gegl_buffer_get_width (mask);
|
||||
|
||||
gimp_edgelset_smooth_normals (es, normal_estimate_mask_size);
|
||||
gimp_edgelset_compute_curvature (es);
|
||||
es = gimp_edgelset_new (mask, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end;
|
||||
|
||||
e = (Edgel **) es->data;
|
||||
|
||||
gimp_edgelset_smooth_normals (es, normal_estimate_mask_size, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end;
|
||||
|
||||
gimp_edgelset_compute_curvature (es, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end;
|
||||
|
||||
while (*e)
|
||||
{
|
||||
const float curvature = ((*e)->curvature > 0.0f) ? (*e)->curvature : 0.0f;
|
||||
const float w = MAX (1e-8f, curvature * curvature);
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
normals[((*e)->x + (*e)->y * width) * 2] += w * (*e)->x_normal;
|
||||
normals[((*e)->x + (*e)->y * width) * 2 + 1] += w * (*e)->y_normal;
|
||||
curvatures[(*e)->x + (*e)->y * width] = MAX (curvature,
|
||||
@ -1403,6 +1536,14 @@ gimp_lineart_compute_normals_curvatures (GeglBuffer *mask,
|
||||
e++;
|
||||
}
|
||||
for (int y = 0; y < gegl_buffer_get_height (mask); ++y)
|
||||
{
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (int x = 0; x < gegl_buffer_get_width (mask); ++x)
|
||||
{
|
||||
const float _angle = atan2f (normals[(x + y * width) * 2 + 1],
|
||||
@ -1410,9 +1551,13 @@ gimp_lineart_compute_normals_curvatures (GeglBuffer *mask,
|
||||
normals[(x + y * width) * 2] = cosf (_angle);
|
||||
normals[(x + y * width) * 2 + 1] = sinf (_angle);
|
||||
}
|
||||
}
|
||||
|
||||
/* Smooth curvatures on edgels, then take maximum on each pixel. */
|
||||
edgels_curvatures = gimp_lineart_get_smooth_curvatures (es);
|
||||
edgels_curvatures = gimp_lineart_get_smooth_curvatures (es, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end;
|
||||
|
||||
smoothed_curvature = edgels_curvatures;
|
||||
|
||||
e = (Edgel **) es->data;
|
||||
@ -1426,13 +1571,17 @@ gimp_lineart_compute_normals_curvatures (GeglBuffer *mask,
|
||||
++smoothed_curvature;
|
||||
e++;
|
||||
}
|
||||
|
||||
end:
|
||||
g_free (edgels_curvatures);
|
||||
|
||||
if (es)
|
||||
g_array_free (es, TRUE);
|
||||
}
|
||||
|
||||
static gfloat *
|
||||
gimp_lineart_get_smooth_curvatures (GArray *edgelset)
|
||||
gimp_lineart_get_smooth_curvatures (GArray *edgelset,
|
||||
GimpAsync *async)
|
||||
{
|
||||
Edgel **e;
|
||||
gfloat *smoothed_curvatures = g_new0 (gfloat, edgelset->len);
|
||||
@ -1453,6 +1602,15 @@ gimp_lineart_get_smooth_curvatures (GArray *edgelset)
|
||||
int n = 5;
|
||||
int i = 1;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
g_free (smoothed_curvatures);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
smoothed_curvature = (*e)->curvature;
|
||||
weights_sum = weights[0];
|
||||
while (n-- && (edgel_after != edgel_before))
|
||||
@ -1480,7 +1638,8 @@ static GArray *
|
||||
gimp_lineart_curvature_extremums (gfloat *curvatures,
|
||||
gfloat *smoothed_curvatures,
|
||||
gint width,
|
||||
gint height)
|
||||
gint height,
|
||||
GimpAsync *async)
|
||||
{
|
||||
gboolean *visited = g_new0 (gboolean, width * height);
|
||||
GQueue *q = g_queue_new ();
|
||||
@ -1489,6 +1648,14 @@ gimp_lineart_curvature_extremums (gfloat *curvatures,
|
||||
max_positions = g_array_new (FALSE, TRUE, sizeof (Pixel));
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
if ((curvatures[x + y * width] > 0.0) && ! visited[x + y * width])
|
||||
@ -1517,6 +1684,13 @@ gimp_lineart_curvature_extremums (gfloat *curvatures,
|
||||
gint p2x;
|
||||
gint p2y;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
p = (Pixel *) g_queue_pop_head (q);
|
||||
sc = smoothed_curvatures[(gint) p->x + (gint) p->y * width];
|
||||
c = curvatures[(gint) p->x + (gint) p->y * width];
|
||||
@ -1667,9 +1841,18 @@ gimp_lineart_curvature_extremums (gfloat *curvatures,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
g_queue_free_full (q, g_free);
|
||||
g_free (visited);
|
||||
|
||||
if (gimp_async_is_stopped (async))
|
||||
{
|
||||
g_array_free (max_positions, TRUE);
|
||||
max_positions = NULL;
|
||||
}
|
||||
|
||||
return max_positions;
|
||||
}
|
||||
|
||||
@ -1695,7 +1878,8 @@ gimp_lineart_find_spline_candidates (GArray *max_positions,
|
||||
gfloat *normals,
|
||||
gint width,
|
||||
gint distance_threshold,
|
||||
gfloat max_angle_deg)
|
||||
gfloat max_angle_deg,
|
||||
GimpAsync *async)
|
||||
{
|
||||
GList *candidates = NULL;
|
||||
const float CosMin = cosf (M_PI * (max_angle_deg / 180.0));
|
||||
@ -1706,6 +1890,15 @@ gimp_lineart_find_spline_candidates (GArray *max_positions,
|
||||
Pixel p1 = g_array_index (max_positions, Pixel, i);
|
||||
gint j;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
g_list_free_full (candidates, g_free);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (j = i + 1; j < max_positions->len; j++)
|
||||
{
|
||||
Pixel p2 = g_array_index (max_positions, Pixel, j);
|
||||
@ -2044,7 +2237,8 @@ gimp_lineart_line_segment_until_hit (const GeglBuffer *mask,
|
||||
}
|
||||
|
||||
static gfloat *
|
||||
gimp_lineart_estimate_strokes_radii (GeglBuffer *mask)
|
||||
gimp_lineart_estimate_strokes_radii (GeglBuffer *mask,
|
||||
GimpAsync *async)
|
||||
{
|
||||
GeglBufferIterator *gi;
|
||||
gfloat *dist;
|
||||
@ -2086,6 +2280,15 @@ gimp_lineart_estimate_strokes_radii (GeglBuffer *mask)
|
||||
gint x;
|
||||
gint y;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gegl_buffer_iterator_stop (gi);
|
||||
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (y = starty; y < endy; y++)
|
||||
for (x = startx; x < endx; x++)
|
||||
{
|
||||
@ -2178,8 +2381,12 @@ gimp_lineart_estimate_strokes_radii (GeglBuffer *mask)
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
g_free (dist);
|
||||
|
||||
if (gimp_async_is_stopped (async))
|
||||
g_clear_pointer (&thickness, g_free);
|
||||
|
||||
return thickness;
|
||||
}
|
||||
|
||||
@ -2401,7 +2608,8 @@ gimp_edgel_region_area (const GeglBuffer *mask,
|
||||
/* Edgel sets */
|
||||
|
||||
static GArray *
|
||||
gimp_edgelset_new (GeglBuffer *buffer)
|
||||
gimp_edgelset_new (GeglBuffer *buffer,
|
||||
GimpAsync *async)
|
||||
{
|
||||
GeglBufferIterator *gi;
|
||||
GArray *set;
|
||||
@ -2442,6 +2650,13 @@ gimp_edgelset_new (GeglBuffer *buffer)
|
||||
gint x;
|
||||
gint y;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (y = starty; y < endy; y++)
|
||||
for (x = startx; x < endx; x++)
|
||||
{
|
||||
@ -2463,10 +2678,21 @@ gimp_edgelset_new (GeglBuffer *buffer)
|
||||
}
|
||||
}
|
||||
|
||||
gimp_edgelset_build_graph (set, buffer, edgel2index);
|
||||
g_hash_table_destroy (edgel2index);
|
||||
gimp_edgelset_build_graph (set, buffer, edgel2index, async);
|
||||
if (gimp_async_is_stopped (async))
|
||||
goto end;
|
||||
|
||||
gimp_edgelset_init_normals (set);
|
||||
|
||||
end:
|
||||
g_hash_table_destroy (edgel2index);
|
||||
|
||||
if (gimp_async_is_stopped (async))
|
||||
{
|
||||
g_array_free (set, TRUE);
|
||||
set = NULL;
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
@ -2501,7 +2727,8 @@ gimp_edgelset_init_normals (GArray *set)
|
||||
|
||||
static void
|
||||
gimp_edgelset_smooth_normals (GArray *set,
|
||||
int mask_size)
|
||||
int mask_size,
|
||||
GimpAsync *async)
|
||||
{
|
||||
const gfloat sigma = mask_size * 0.775;
|
||||
const gfloat den = 2 * sigma * sigma;
|
||||
@ -2523,6 +2750,13 @@ gimp_edgelset_smooth_normals (GArray *set,
|
||||
int n = mask_size;
|
||||
int i = 1;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
smoothed_normal = Direction2Normal[it->direction];
|
||||
while (n-- && (edgel_after != edgel_before))
|
||||
{
|
||||
@ -2541,7 +2775,8 @@ gimp_edgelset_smooth_normals (GArray *set,
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_edgelset_compute_curvature (GArray *set)
|
||||
gimp_edgelset_compute_curvature (GArray *set,
|
||||
GimpAsync *async)
|
||||
{
|
||||
gint i;
|
||||
|
||||
@ -2558,13 +2793,21 @@ gimp_edgelset_compute_curvature (GArray *set)
|
||||
const float crossp = n_prev.x * n_next.y - n_prev.y * n_next.x;
|
||||
|
||||
it->curvature = (crossp > 0.0f) ? c : -c;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_edgelset_build_graph (GArray *set,
|
||||
GeglBuffer *buffer,
|
||||
GHashTable *edgel2index)
|
||||
GHashTable *edgel2index,
|
||||
GimpAsync *async)
|
||||
{
|
||||
Edgel edgel;
|
||||
gint i;
|
||||
@ -2575,6 +2818,13 @@ gimp_edgelset_build_graph (GArray *set,
|
||||
Edgel *it = g_array_index (set, Edgel *, i);
|
||||
guint neighbor_pos;
|
||||
|
||||
if (gimp_async_is_canceled (async))
|
||||
{
|
||||
gimp_async_abort (async);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gimp_edgelset_next8 (buffer, it, &edgel);
|
||||
|
||||
gimp_assert (g_hash_table_contains (edgel2index, &edgel));
|
||||
|
Reference in New Issue
Block a user