[Bf-blender-cvs] [87d5bd5fb06] temp-gpencil-bezier-stroke-type: GPencil: Implement Merge by Distance for curves

Falk David noreply at git.blender.org
Wed May 5 14:43:09 CEST 2021


Commit: 87d5bd5fb06340ecfd543518490e6278a9b83ee0
Author: Falk David
Date:   Wed May 5 14:42:56 2021 +0200
Branches: temp-gpencil-bezier-stroke-type
https://developer.blender.org/rB87d5bd5fb06340ecfd543518490e6278a9b83ee0

GPencil: Implement Merge by Distance for curves

This commit adds the `BKE_gpencil_editcurve_merge_distance` function.
It will merge the control points by distance (always at the first point).

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

M	source/blender/blenkernel/BKE_gpencil_curve.h
M	source/blender/blenkernel/intern/gpencil_curve.c
M	source/blender/editors/gpencil/gpencil_edit.c

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

diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index e213cf7a4c5..bc3f8208ac3 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -87,6 +87,11 @@ void BKE_gpencil_editcurve_smooth(struct bGPDstroke *gps,
                                   const bool do_positions,
                                   const bool do_pressure,
                                   const bool do_strength);
+bool BKE_gpencil_editcurve_merge_distance(struct bGPDstroke *gps,
+                                          const float threshold,
+                                          const bool use_unselected,
+                                          const bool refit_segments,
+                                          const float error_threshold);
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 858e09034b8..5a32b135b42 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -2341,4 +2341,70 @@ void BKE_gpencil_editcurve_smooth(bGPDstroke *gps,
   }
 }
 
+/**
+ * Curve Merge by Distance
+ * Merge the control points by distance. Merging will always occur on the first point.
+ * The first and last point are never merged. Note: The caller is resposible for the geometry
+ * update of the stroke.
+ * \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.
+ * \param refit_segments: Set to refit segments where points were dissolved.
+ * \param error_threshold: Error threshold for refitting (only used when refit_segments = true).
+ * \returns True if any point was merged and the geometry changed.
+ */
+bool BKE_gpencil_editcurve_merge_distance(bGPDstroke *gps,
+                                          const float threshold,
+                                          const bool use_unselected,
+                                          const bool refit_segments,
+                                          const float error_threshold)
+{
+  bGPDcurve *gpc = gps->editcurve;
+  if (gpc == NULL || gpc->tot_curve_points < 2 || threshold == 0.0f) {
+    return false;
+  }
+  const float th_square = threshold * threshold;
+
+  bool tagged = false;
+  int i = 0, step = 1;
+  while ((i < gpc->tot_curve_points - 1) && (i + step < gpc->tot_curve_points)) {
+    bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
+    bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + step];
+    if ((!use_unselected && ((gpc_pt->flag & GP_CURVE_POINT_SELECT) == 0 ||
+                             (gpc_pt_next->flag & GP_CURVE_POINT_SELECT) == 0)) ||
+        (gpc_pt->flag & GP_CURVE_POINT_TAG)) {
+      i++;
+      step = 1;
+      continue;
+    }
+    if (gpc_pt_next->flag & GP_CURVE_POINT_TAG) {
+      step++;
+      continue;
+    }
+    BezTriple *bezt = &gpc_pt->bezt;
+    BezTriple *bezt_next = &gpc_pt_next->bezt;
+
+    float len_square = len_squared_v3v3(bezt->vec[1], bezt_next->vec[1]);
+    if (len_square <= th_square) {
+      gpc_pt_next->flag |= GP_CURVE_POINT_TAG;
+      tagged = true;
+      step++;
+    }
+    else {
+      i++;
+      step = 1;
+    }
+  }
+
+  gpc->curve_points[0].flag &= ~GP_CURVE_POINT_TAG;
+  gpc->curve_points[gpc->tot_curve_points - 1].flag &= ~GP_CURVE_POINT_TAG;
+
+  int old_num_points = gpc->tot_curve_points;
+  if (tagged) {
+    return BKE_gpencil_editcurve_dissolve(
+               gps, GP_CURVE_POINT_TAG, refit_segments, error_threshold) != old_num_points;
+  }
+  return false;
+}
+
 /** \} */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 2299a1a42f4..c90d255c413 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -5624,24 +5624,31 @@ static int gpencil_merge_by_distance_exec(bContext *C, wmOperator *op)
     return OPERATOR_CANCELLED;
   }
 
-  const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
-
-  if (is_curve_edit) {
-    /* TODO: merge curve points by distance */
-  }
-  else {
-    /* Go through each editable selected stroke */
-    GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
-      if (gps->flag & GP_STROKE_SELECT) {
-        BKE_gpencil_stroke_merge_distance(gpd, gpf_, gps, threshold, unselected);
+  bool changed = false;
+  /* Go through each editable selected stroke */
+  GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+    if (GPENCIL_STROKE_TYPE_BEZIER(gps)) {
+      bGPDcurve *gpc = gps->editcurve;
+      if (gpc->flag & GP_CURVE_SELECT) {
+        /* TODO: don't hardcode the refit and threshold. Figure out how to set these. */
+        if (BKE_gpencil_editcurve_merge_distance(gps, threshold, unselected, false, 0.0f)) {
+          BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT);
+          changed = true;
+        }
       }
     }
-    GP_EDITABLE_STROKES_END(gpstroke_iter);
+    else if (gps->flag & GP_STROKE_SELECT) {
+      BKE_gpencil_stroke_merge_distance(gpd, gpf_, gps, threshold, unselected);
+      changed = true;
+    }
   }
+  GP_EDITABLE_STROKES_END(gpstroke_iter);
 
-  /* notifiers */
-  DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
-  WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+  if (changed) {
+    /* notifiers */
+    DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+    WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+  }
 
   return OPERATOR_FINISHED;
 }



More information about the Bf-blender-cvs mailing list