[Bf-blender-cvs] [e9607f45d85] master: GPencil: Automerge last drawn stroke with previous strokes

Antonio Vazquez noreply at git.blender.org
Wed Nov 18 21:38:41 CET 2020


Commit: e9607f45d85df6df834a80f147b8c42ff12f56f2
Author: Antonio  Vazquez
Date:   Wed Nov 18 21:30:43 2020 +0100
Branches: master
https://developer.blender.org/rBe9607f45d85df6df834a80f147b8c42ff12f56f2

GPencil: Automerge last drawn stroke with previous strokes

This option joins any stroke with an end near  the actual stroke. Now it is not limited to the last stroke, any stroke in the same layer for the actual frame can be joined. The join can join two strokes drawing a third stroke.

If the end and the start of the result stroke are very small, the stroke is changed to be cyclic automatically.

There is a limit distance to join the stroke, if the distance is greater than this value, the strokes are not joined. Actually, a constant, threshold distance is used, but we could expose 
as a parameter in the UI in the future.

The tool can be used with freehand drawing or with primitives.

Note: Great part of the patch is just a refactor of the old code to make it accessible and to keep code organized.

Reviewed By: mendio

Maniphest Tasks: T82377

Differential Revision: https://developer.blender.org/D9440

===================================================================

M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/blenkernel/BKE_gpencil_geom.h
M	source/blender/blenkernel/intern/gpencil_geom.c
M	source/blender/editors/gpencil/annotate_paint.c
M	source/blender/editors/gpencil/gpencil_convert.c
M	source/blender/editors/gpencil/gpencil_edit.c
M	source/blender/editors/gpencil/gpencil_intern.h
M	source/blender/editors/gpencil/gpencil_merge.c
M	source/blender/editors/gpencil/gpencil_paint.c
M	source/blender/editors/gpencil/gpencil_primitive.c
M	source/blender/editors/gpencil/gpencil_utils.c
M	source/blender/editors/include/ED_gpencil.h
M	source/blender/makesdna/DNA_scene_types.h
M	source/blender/makesrna/intern/rna_scene.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 9dbb56e7e45..e0c28983544 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -657,6 +657,8 @@ class VIEW3D_HT_header(Header):
                 sub.prop(tool_settings, "use_gpencil_weight_data_add", text="", icon='WPAINT_HLT')
                 sub.separator(factor=0.4)
                 sub.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
+                sub.separator(factor=0.4)
+                sub.prop(tool_settings, "use_gpencil_automerge_strokes", text="")
 
             # Select mode for Editing
             if gpd.use_stroke_edit_mode:
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 6917a62053c..b107a6e72af 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -37,6 +37,7 @@ struct bGPDlayer;
 struct bGPDspoint;
 struct bGPDstroke;
 struct bGPdata;
+struct bGPDcurve;
 
 /* Object boundbox. */
 bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);
@@ -115,6 +116,21 @@ bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps, const float dist, const
 bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
                                     const int index_from,
                                     const int index_to);
+struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
+                                                           struct bGPDframe *gpf,
+                                                           struct bGPDstroke *gps,
+                                                           struct bGPDstroke *next_stroke,
+                                                           int tag_flags,
+                                                           bool select,
+                                                           int limit);
+void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
+                                            struct bGPDframe *gpf,
+                                            struct bGPDstroke *gps,
+                                            struct bGPDstroke *next_stroke,
+                                            struct bGPDcurve *gpc,
+                                            int tag_flags);
+
+void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
 bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
                               struct bGPDframe *gpf,
                               struct bGPDstroke *gps,
@@ -123,9 +139,18 @@ bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
 bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist);
 
 float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
+float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
+                                        const int start_index,
+                                        const int end_index,
+                                        bool use_3d);
 
 void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps);
 
+void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
+                             struct bGPDstroke *gps_b,
+                             const bool leave_gaps,
+                             const bool fit_thickness);
+
 bool BKE_gpencil_convert_mesh(struct Main *bmain,
                               struct Depsgraph *depsgraph,
                               struct Scene *scene,
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index d2cfb36cb15..fc74439fd76 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -1345,6 +1345,34 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
   return total_length;
 }
 
+/** Calculate grease pencil stroke length between points. */
+float BKE_gpencil_stroke_segment_length(const struct bGPDstroke *gps,
+                                        const int start_index,
+                                        const int end_index,
+                                        bool use_3d)
+{
+  if (!gps->points || gps->totpoints < 2 || end_index <= start_index) {
+    return 0.0f;
+  }
+
+  int index = MAX2(start_index, 0) + 1;
+  int last_index = MIN2(end_index, gps->totpoints - 1) + 1;
+
+  float *last_pt = &gps->points[index - 1].x;
+  float total_length = 0.0f;
+  for (int i = index; i < last_index; i++) {
+    bGPDspoint *pt = &gps->points[i];
+    if (use_3d) {
+      total_length += len_v3v3(&pt->x, last_pt);
+    }
+    else {
+      total_length += len_v2v2(&pt->x, last_pt);
+    }
+    last_pt = &pt->x;
+  }
+  return total_length;
+}
+
 /**
  * Trim stroke to the first intersection or loop.
  * \param gps: Stroke data
@@ -2640,4 +2668,560 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps)
     copy_v4_v4(pt->vert_color, color);
   }
 }
+
+/* Flip stroke. */
+void BKE_gpencil_stroke_flip(bGPDstroke *gps)
+{
+  int end = gps->totpoints - 1;
+
+  for (int i = 0; i < gps->totpoints / 2; i++) {
+    bGPDspoint *point, *point2;
+    bGPDspoint pt;
+
+    /* save first point */
+    point = &gps->points[i];
+    pt.x = point->x;
+    pt.y = point->y;
+    pt.z = point->z;
+    pt.flag = point->flag;
+    pt.pressure = point->pressure;
+    pt.strength = point->strength;
+    pt.time = point->time;
+    copy_v4_v4(pt.vert_color, point->vert_color);
+
+    /* replace first point with last point */
+    point2 = &gps->points[end];
+    point->x = point2->x;
+    point->y = point2->y;
+    point->z = point2->z;
+    point->flag = point2->flag;
+    point->pressure = point2->pressure;
+    point->strength = point2->strength;
+    point->time = point2->time;
+    copy_v4_v4(point->vert_color, point2->vert_color);
+
+    /* replace last point with first saved before */
+    point = &gps->points[end];
+    point->x = pt.x;
+    point->y = pt.y;
+    point->z = pt.z;
+    point->flag = pt.flag;
+    point->pressure = pt.pressure;
+    point->strength = pt.strength;
+    point->time = pt.time;
+    copy_v4_v4(point->vert_color, pt.vert_color);
+
+    end--;
+  }
+}
+
+/* Temp data for storing information about an "island" of points
+ * that should be kept when splitting up a stroke. Used in:
+ * gpencil_stroke_delete_tagged_points()
+ */
+typedef struct tGPDeleteIsland {
+  int start_idx;
+  int end_idx;
+} tGPDeleteIsland;
+
+static void gpencil_stroke_join_islands(bGPdata *gpd,
+                                        bGPDframe *gpf,
+                                        bGPDstroke *gps_first,
+                                        bGPDstroke *gps_last)
+{
+  bGPDspoint *pt = NULL;
+  bGPDspoint *pt_final = NULL;
+  const int totpoints = gps_first->totpoints + gps_last->totpoints;
+
+  /* create new stroke */
+  bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false, true);
+
+  join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
+  join_stroke->totpoints = totpoints;
+  join_stroke->flag &= ~GP_STROKE_CYCLIC;
+
+  /* copy points (last before) */
+  int e1 = 0;
+  int e2 = 0;
+  float delta = 0.0f;
+
+  for (int i = 0; i < totpoints; i++) {
+    pt_final = &join_stroke->points[i];
+    if (i < gps_last->totpoints) {
+      pt = &gps_last->points[e1];
+      e1++;
+    }
+    else {
+      pt = &gps_first->points[e2];
+      e2++;
+    }
+
+    /* copy current point */
+    copy_v3_v3(&pt_final->x, &pt->x);
+    pt_final->pressure = pt->pressure;
+    pt_final->strength = pt->strength;
+    pt_final->time = delta;
+    pt_final->flag = pt->flag;
+    copy_v4_v4(pt_final->vert_color, pt->vert_color);
+
+    /* retiming with fixed time interval (we cannot determine real time) */
+    delta += 0.01f;
+  }
+
+  /* Copy over vertex weight data (if available) */
+  if ((gps_first->dvert != NULL) || (gps_last->dvert != NULL)) {
+    join_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * totpoints, __func__);
+    MDeformVert *dvert_src = NULL;
+    MDeformVert *dvert_dst = NULL;
+
+    /* Copy weights (last before)*/
+    e1 = 0;
+    e2 = 0;
+    for (int i = 0; i < totpoints; i++) {
+      dvert_dst = &join_stroke->dvert[i];
+      dvert_src = NULL;
+      if (i < gps_last->totpoints) {
+        if (gps_last->dvert) {
+          dvert_src = &gps_last->dvert[e1];
+          e1++;
+        }
+      }
+      else {
+        if (gps_first->dvert) {
+          dvert_src = &gps_first->dvert[e2];
+          e2++;
+        }
+      }
+
+      if ((dvert_src) && (dvert_src->dw)) {
+        dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
+      }
+    }
+  }
+
+  /* add new stroke at head */
+  BLI_addhead(&gpf->strokes, join_stroke);
+  /* Calc geometry data. */
+  BKE_gpencil_stroke_geometry_update(gpd, join_stroke);
+
+  /* remove first stroke */
+  BLI_remlink(&gpf->strokes, gps_first);
+  BKE_gpencil_free_stroke(gps_first);
+
+  /* remove last stroke */
+  BLI_remlink(&gpf->strokes, gps_last);
+  BKE_gpencil_free_stroke(gps_last);
+}
+
+/* Split the given stroke into several new strokes, partitioning
+ * it based on whether the stroke points have a particular flag
+ * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
+ *
+ * The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-tagged points
+ *    which will all end up being in new strokes.
+ *    - In the most extreme case (i.e. every other vert is a 1-vert island),
+ *      we have at most n / 2 islands
+ *    - Once we start having larger islands than that, the number required
+ *      becomes much less
+ * 2) Each island gets converted to a new stroke
+ * If the number of points is <= limit, the stroke is deleted
+ */
+bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd,
+                                                    bGPDframe *gpf,
+                                                    bGPDstroke *gps,
+                                                    bGPDstroke *next_stroke,
+                                                    int

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list