[Bf-blender-cvs] [eb5591fc9ab] temp-gpencil-bezier-stroke-type: GPencil: Simplify fixed for bezier strokes

Falk David noreply at git.blender.org
Sun Mar 21 16:19:54 CET 2021


Commit: eb5591fc9aba318c79635e4e6e677705ba4f3e53
Author: Falk David
Date:   Sun Mar 21 16:19:46 2021 +0100
Branches: temp-gpencil-bezier-stroke-type
https://developer.blender.org/rBeb5591fc9aba318c79635e4e6e677705ba4f3e53

GPencil: Simplify fixed for bezier strokes

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

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 e6fa16a64d5..bb3247d489c 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -71,6 +71,7 @@ void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
 void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
 void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
 void BKE_gpencil_editcurve_simplify_adaptive(struct bGPDstroke *gps, const float threshold);
+void BKE_gpencil_editcurve_simplify_fixed(struct bGPDstroke *gps, const int count);
 
 #ifdef __cplusplus
 }
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index d66ada53844..b4d41844887 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -1751,8 +1751,77 @@ void BKE_gpencil_editcurve_subdivide(bGPDstroke *gps, const int cuts)
   }
 }
 
-void gpencil_editcurve_dissolve_single_smallest_error()
+/* Helper: Dissolve the curve point with the lowest re-fit error. Dissolve only if error is under
+ * `threshold`. Returns true if a point was dissolved. */
+static bool gpencil_editcurve_dissolve_smallest_error_curve_point(bGPDstroke *gps,
+                                                                  bGPDcurve *gpc,
+                                                                  const float diag_length,
+                                                                  const bool is_cyclic,
+                                                                  const float threshold)
 {
+  bool changed = false;
+  /* Duplicate the curve point array. */
+  bGPDcurve_point *curve_point_array = MEM_dupallocN(gpc->curve_points);
+
+  float lowest_error = FLT_MAX;
+  int lowest_error_idx = 0;
+  /* Loop over control point pairs with one control point in between.
+   * Find the control point that produces the lowest error when removed. */
+  for (int i = 0; i < gpc->tot_curve_points - 2; i++) {
+    bGPDcurve_point *cpt_prev = &curve_point_array[i];
+    bGPDcurve_point *cpt_next = &curve_point_array[i + 2];
+
+    float error_sq;
+    /* Regenerate the handles between cpt_prev and cpt_next as if the point in the middle didn't
+     * exist. Get the re-fit error. */
+    gpencil_stroke_editcurve_regenerate_single_ex(cpt_prev,
+                                                  cpt_next,
+                                                  gps->points,
+                                                  gps->totpoints,
+                                                  gps->boundbox_min,
+                                                  diag_length,
+                                                  is_cyclic,
+                                                  0.0f,
+                                                  &error_sq);
+
+    if (error_sq < lowest_error) {
+      lowest_error = error_sq;
+      lowest_error_idx = i + 1;
+    }
+  }
+
+  /* Dissolve the control point with the lowest error found. */
+  if (sqrtf(lowest_error) < threshold) {
+    int new_tot_curve_points = gpc->tot_curve_points - 1;
+    bGPDcurve_point *new_points = MEM_callocN(sizeof(bGPDcurve_point) * new_tot_curve_points,
+                                              __func__);
+    /* Copy all other points. Skip the point that will be dissolved. */
+    memcpy(new_points, gpc->curve_points, lowest_error_idx * sizeof(bGPDcurve_point));
+    memcpy(new_points + lowest_error_idx,
+           gpc->curve_points + lowest_error_idx + 1,
+           (new_tot_curve_points - lowest_error_idx) * sizeof(bGPDcurve_point));
+
+    /* Get the start and end points of the segment. */
+    bGPDcurve_point *cpt_start = &curve_point_array[lowest_error_idx - 1];
+    bGPDcurve_point *cpt_end = &curve_point_array[lowest_error_idx + 1];
+    bGPDcurve_point *new_cpt_start = &new_points[lowest_error_idx - 1];
+    bGPDcurve_point *new_cpt_end = &new_points[lowest_error_idx];
+
+    /* Write the new handles. */
+    copy_v3_v3(new_cpt_start->bezt.vec[2], cpt_start->bezt.vec[2]);
+    copy_v3_v3(new_cpt_end->bezt.vec[0], cpt_end->bezt.vec[0]);
+
+    /* Overwrite curve points. */
+    MEM_freeN(gpc->curve_points);
+    gpc->curve_points = new_points;
+    gpc->tot_curve_points = new_tot_curve_points;
+
+    changed = true;
+  }
+
+  MEM_freeN(curve_point_array);
+
+  return changed;
 }
 
 /**
@@ -1768,67 +1837,32 @@ void BKE_gpencil_editcurve_simplify_adaptive(bGPDstroke *gps, const float thresh
   const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
   const float diag_length = len_v3v3(gps->boundbox_min, gps->boundbox_max);
 
-  float lowest_error = 0;
+  bool changed = true;
   /* Loop until we have removed all points that causes an error less than `threshold`. */
-  while (gpc->tot_curve_points > 2 && sqrtf(lowest_error) < threshold) {
-    /* Duplicate the curve point array. */
-    bGPDcurve_point *curve_point_array = MEM_dupallocN(gpc->curve_points);
-
-    lowest_error = FLT_MAX;
-    int lowest_error_idx = 0;
-    /* Loop over control point pairs with one control point in between.
-     * Find the control point that produces the lowest error when removed. */
-    for (int i = 0; i < gpc->tot_curve_points - 2; i++) {
-      bGPDcurve_point *cpt_prev = &curve_point_array[i];
-      bGPDcurve_point *cpt_next = &curve_point_array[i + 2];
-
-      float error_sq;
-      /* Regenerate the handles between cpt_prev and cpt_next as if the point in the middle didn't
-       * exist. Get the re-fit error. */
-      gpencil_stroke_editcurve_regenerate_single_ex(cpt_prev,
-                                                    cpt_next,
-                                                    gps->points,
-                                                    gps->totpoints,
-                                                    gps->boundbox_min,
-                                                    diag_length,
-                                                    is_cyclic,
-                                                    0.0f,
-                                                    &error_sq);
-
-      if (error_sq < lowest_error) {
-        lowest_error = error_sq;
-        lowest_error_idx = i + 1;
-      }
-    }
+  while (gpc->tot_curve_points > 2 && changed) {
+    changed = gpencil_editcurve_dissolve_smallest_error_curve_point(
+        gps, gpc, diag_length, is_cyclic, threshold);
+  }
+}
 
-    /* Dissolve the control point with the lowest error found. */
-    if (sqrtf(lowest_error) < threshold) {
-      int new_tot_curve_points = gpc->tot_curve_points - 1;
-      bGPDcurve_point *new_points = MEM_callocN(sizeof(bGPDcurve_point) * new_tot_curve_points,
-                                                __func__);
-      /* Copy all other points. Skip the point that will be dissolved. */
-      memcpy(new_points, gpc->curve_points, lowest_error_idx * sizeof(bGPDcurve_point));
-      memcpy(new_points + lowest_error_idx,
-             gpc->curve_points + lowest_error_idx + 1,
-             (new_tot_curve_points - lowest_error_idx) * sizeof(bGPDcurve_point));
-
-      /* Get the start and end points of the segment. */
-      bGPDcurve_point *cpt_start = &curve_point_array[lowest_error_idx - 1];
-      bGPDcurve_point *cpt_end = &curve_point_array[lowest_error_idx + 1];
-      bGPDcurve_point *new_cpt_start = &new_points[lowest_error_idx - 1];
-      bGPDcurve_point *new_cpt_end = &new_points[lowest_error_idx];
-
-      /* Write the new handles. */
-      copy_v3_v3(new_cpt_start->bezt.vec[2], cpt_start->bezt.vec[2]);
-      copy_v3_v3(new_cpt_end->bezt.vec[0], cpt_end->bezt.vec[0]);
-
-      /* Overwrite curve points. */
-      MEM_freeN(gpc->curve_points);
-      gpc->curve_points = new_points;
-      gpc->tot_curve_points = new_tot_curve_points;
-    }
+/**
+ * Simplify Fixed
+ * Dissolves `count` curve points with the lowest refit-error.
+ */
+void BKE_gpencil_editcurve_simplify_fixed(bGPDstroke *gps, const int count)
+{
+  bGPDcurve *gpc = gps->editcurve;
+  if (gpc == NULL || gpc->tot_curve_points < 3 || count < 1) {
+    return;
+  }
+  const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
+  const float diag_length = len_v3v3(gps->boundbox_min, gps->boundbox_max);
 
-    MEM_freeN(curve_point_array);
+  /* Loop until we have removed all points that causes an error less than `threshold`. */
+  for (int i = count; i >= 0 && gpc->tot_curve_points > 2; i--) {
+    gpencil_editcurve_dissolve_smallest_error_curve_point(
+        gps, gpc, diag_length, is_cyclic, FLT_MAX);
   }
 }
+
 /** \} */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 936b5b590bf..ddb9d8f3897 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -4585,24 +4585,27 @@ static int gpencil_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
     return OPERATOR_CANCELLED;
   }
 
-  const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
-
   bool changed = false;
-  if (is_curve_edit) {
-    BKE_report(op->reports, RPT_ERROR, "Not implemented!");
-  }
-  else {
-    /* Go through each editable + selected stroke */
-    GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
-      if (gps->flag & GP_STROKE_SELECT) {
-        changed |= true;
-        for (int i = 0; i < steps; i++) {
-          BKE_gpencil_stroke_simplify_fixed(gpd, gps);
-        }
+  /* 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) {
+        BKE_gpencil_editcurve_simplify_fixed(gps, steps);
+        BKE_gpencil_editcurve_recalculate_handles(gps);
+        gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+        BKE_gpencil_stroke_geometry_update(gpd, gps);
+        changed = true;
       }
     }
-    GP_EDITABLE_STROKES_END(gpstroke_iter);
+    else if (gps->flag & GP_STROKE_SELECT) {
+      for (int i = 0; i < steps; i++) {
+        BKE_gpencil_str

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list