From b9d0f33530f095fb318890dca4f8933a9afd1904 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Thu, 8 Aug 2019 10:23:05 +0200 Subject: Fix T67545: GPencil - New Merge by Distance operator Merge points when the distance is less than a predefined value. The method to interpolate the position created a wrong merge. Now, always the secondary point is merged with the first one (merge at first), except the last point. --- source/blender/blenkernel/BKE_gpencil.h | 4 ++ source/blender/blenkernel/intern/gpencil.c | 78 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 9ec872f3676..3dfd6eb466c 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -197,6 +197,10 @@ void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor); void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps); void BKE_gpencil_subdivide(struct bGPDstroke *gps, int level, int flag); bool BKE_gpencil_trim_stroke(struct bGPDstroke *gps); +void BKE_gpencil_merge_distance_stroke(struct bGPDframe *gpf, + struct bGPDstroke *gps, + const float threshold, + const bool use_unselected); void BKE_gpencil_stroke_2d_flat(const struct bGPDspoint *points, int totpoints, diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 3ae20642b15..efdb35d4409 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -2138,3 +2138,81 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta gps->tot_triangles = 0; } } + +/* Merge by distance ------------------------------------- */ +/* Reduce a series of points when the distance is below a threshold. + * Special case for first and last points (both are keeped) for other points, + * the merge point always is at first point. + * \param gpf: Grease Pencil frame + * \param gps: Grease Pencil stroke + * \param threshold: Distance between points + * \param use_unselected: Set to true to analyze all stroke and not only selected points + */ +void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf, + bGPDstroke *gps, + const float threshold, + const bool use_unselected) +{ + bGPDspoint *pt = NULL; + bGPDspoint *pt_next = NULL; + float tagged = false; + /* Use square distance to speed up loop */ + const float th_square = threshold * threshold; + /* Need to have something to merge. */ + if (gps->totpoints < 2) { + return; + } + int i = 0; + int step = 1; + while ((i < gps->totpoints - 1) && (i + step < gps->totpoints)) { + pt = &gps->points[i]; + if (pt->flag & GP_SPOINT_TAG) { + i++; + step = 1; + continue; + } + pt_next = &gps->points[i + step]; + /* Do not recalc tagged points. */ + if (pt_next->flag & GP_SPOINT_TAG) { + step++; + continue; + } + /* Check if contiguous points are selected. */ + if (!use_unselected) { + if (((pt->flag & GP_SPOINT_SELECT) == 0) || ((pt_next->flag & GP_SPOINT_SELECT) == 0)) { + i++; + step = 1; + continue; + } + } + float len_square = len_squared_v3v3(&pt->x, &pt_next->x); + if (len_square <= th_square) { + tagged = true; + if (i != gps->totpoints - 1) { + /* Tag second point for delete. */ + pt_next->flag |= GP_SPOINT_TAG; + } + else { + pt->flag |= GP_SPOINT_TAG; + } + /* Jump to next pair of points, keeping first point segment equals.*/ + step++; + } + else { + /* Analyze next point. */ + i++; + step = 1; + } + } + + /* Always untag extremes. */ + pt = &gps->points[0]; + pt->flag &= ~GP_SPOINT_TAG; + pt = &gps->points[gps->totpoints - 1]; + pt->flag &= ~GP_SPOINT_TAG; + + /* Dissolve tagged points */ + if (tagged) { + BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG); + } +} -- cgit v1.2.3