[Bf-blender-cvs] [9a753fd70a9] temp-gpencil-bezier-stroke-type: GPencil: Refactor dissolve
Falk David
noreply at git.blender.org
Sun May 2 18:10:15 CEST 2021
Commit: 9a753fd70a92816a2c51b128570cb001fce97fbc
Author: Falk David
Date: Sun May 2 18:07:13 2021 +0200
Branches: temp-gpencil-bezier-stroke-type
https://developer.blender.org/rB9a753fd70a92816a2c51b128570cb001fce97fbc
GPencil: Refactor dissolve
This change introduces a new BKE function to desolve curve points and
then refactors the dissolve operator to make use of this function. This
simplifies the code a lot.
===================================================================
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 b4767b3fcfc..e213cf7a4c5 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -72,6 +72,10 @@ void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
const enum eGPStrokeGeoUpdateFlag flag);
bool BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
+int BKE_gpencil_editcurve_dissolve(struct bGPDstroke *gps,
+ const uint flag,
+ const bool refit_segments,
+ const float error_threshold);
void BKE_gpencil_editcurve_simplify_adaptive(struct bGPDstroke *gps, const float threshold);
void BKE_gpencil_editcurve_simplify_fixed(struct bGPDstroke *gps, const int count);
void BKE_gpencil_editcurve_smooth(struct bGPDstroke *gps,
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 1ab6a1283a5..858e09034b8 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -1166,9 +1166,9 @@ void BKE_gpencil_stroke_editcurve_regenerate_single(bGPDstroke *gps,
* \param flag: Flag for refitting options (see eGPStrokeGeoUpdateFlag).
*/
void BKE_gpencil_stroke_refit_curve(bGPDstroke *gps,
- const float threshold,
- const float corner_angle,
- const eGPStrokeGeoUpdateFlag flag)
+ const float threshold,
+ const float corner_angle,
+ const eGPStrokeGeoUpdateFlag flag)
{
if (gps == NULL || gps->totpoints < 0) {
return;
@@ -1906,6 +1906,9 @@ void BKE_gpencil_editcurve_subdivide(bGPDstroke *gps, const int cuts)
bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
/* repeat for number of cuts */
+ /* TODO: Ideally the subdivisions should match how it works in the rest of Blender. Here we get
+ * 1->1, 2->3, 3->7 etc. because we keep supdividing already subdivided segments. But it would be
+ * better to get the exact number of cuts per segment.*/
for (int s = 0; s < cuts; s++) {
int old_tot_curve_points = gpc->tot_curve_points;
int new_num_curve_points = gpencil_editcurve_subdivide_count(gpc, is_cyclic);
@@ -1978,6 +1981,116 @@ void BKE_gpencil_editcurve_subdivide(bGPDstroke *gps, const int cuts)
}
}
+static void gpencil_refit_single_from_to(bGPDstroke *gps,
+ bGPDcurve *gpc,
+ bGPDcurve_point *new_points,
+ int from_start,
+ int from_end,
+ int to_start,
+ int to_end,
+ float error_threshold)
+{
+ bGPDcurve_point *cpt_start = &gpc->curve_points[from_start];
+ bGPDcurve_point *cpt_end = &gpc->curve_points[from_end];
+ bGPDcurve_point *new_cpt_start = &new_points[to_start];
+ bGPDcurve_point *new_cpt_end = &new_points[to_end];
+
+ BKE_gpencil_stroke_editcurve_regenerate_single(gps, from_start, from_end, error_threshold);
+
+ memcpy(new_cpt_start, cpt_start, sizeof(bGPDcurve_point));
+ memcpy(new_cpt_end, cpt_end, sizeof(bGPDcurve_point));
+}
+
+/**
+ * Dissolves the curve points tagged with `flag`.
+ * \param gps: The stroke.
+ * \param flag: flag (see eGPDcurve_point_Flag).
+ * \param refit_segments: Do a refit of the segments where points have been dissolved.
+ * \param error_threshold: Refit threshold when refitting.
+ *
+ * \returns The number of points that remain after dissolving. Can be 0 in which case the caller
+ * should delete the stroke.
+ */
+int BKE_gpencil_editcurve_dissolve(bGPDstroke *gps,
+ const uint flag,
+ const bool refit_segments,
+ const float error_threshold)
+{
+ bGPDcurve *gpc = gps->editcurve;
+ if (gpc == NULL || gpc->tot_curve_points < 2) {
+ return gpc->tot_curve_points;
+ }
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC);
+
+ int first = -1, last = 0;
+ int num_points_remaining = gpc->tot_curve_points;
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ if ((cpt->flag & flag)) {
+ num_points_remaining--;
+ }
+ else {
+ if (first < 0) {
+ first = i;
+ }
+ last = i;
+ }
+ }
+
+ /* All points will be deleted. */
+ if (num_points_remaining < 1) {
+ return 0;
+ }
+ /* All points remain. */
+ else if (num_points_remaining == gpc->tot_curve_points) {
+ return gpc->tot_curve_points;
+ }
+
+ bGPDcurve_point *new_points = MEM_callocN(sizeof(bGPDcurve_point) * num_points_remaining,
+ __func__);
+
+ int new_idx = 0, start = first, end = first;
+ for (int i = first; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *cpt = &gpc->curve_points[i];
+ bGPDcurve_point *new_cpt = &new_points[new_idx];
+ if ((cpt->flag & flag) == 0) {
+ memcpy(new_cpt, cpt, sizeof(bGPDcurve_point));
+ /* Check that the indices are in bounds. */
+ if (refit_segments && (start > 0) && IN_RANGE(end, start, gpc->tot_curve_points)) {
+ /* Refit this segment. */
+ gpencil_refit_single_from_to(
+ gps, gpc, new_points, start - 1, end, new_idx - 1, new_idx, error_threshold);
+ start = end = i;
+ }
+ new_idx++;
+ start++;
+ }
+ end++;
+ }
+
+ if (is_cyclic && refit_segments) {
+ /* Make sure that there is at least one segment that needs updating. */
+ if (last != first && first >= 0 && last >= 0 &&
+ !(first == 0 && last == (gpc->tot_curve_points - 1))) {
+
+ /* Refit this segment. */
+ gpencil_refit_single_from_to(
+ gps, gpc, new_points, last, first, num_points_remaining - 1, 0, error_threshold);
+ }
+ }
+
+ /* Recreate array. */
+ if (gpc->curve_points != NULL) {
+ MEM_freeN(gpc->curve_points);
+ }
+
+ gpc->curve_points = new_points;
+ gpc->tot_curve_points = num_points_remaining;
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+
+ return num_points_remaining;
+}
+
/* 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,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 5c270d5ffc9..2299a1a42f4 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -2302,57 +2302,28 @@ static int gpencil_delete_selected_strokes(bContext *C)
/* ----------------------------------- */
-static void gpencil_refit_single_from_to(bGPDstroke *gps,
- bGPDcurve *gpc,
- bGPDcurve_point *new_points,
- int from_start,
- int from_end,
- int to_start,
- int to_end,
- float error_threshold)
-{
- bGPDcurve_point *cpt_start = &gpc->curve_points[from_start];
- bGPDcurve_point *cpt_end = &gpc->curve_points[from_end];
- bGPDcurve_point *new_cpt_start = &new_points[to_start];
- bGPDcurve_point *new_cpt_end = &new_points[to_end];
-
- BKE_gpencil_stroke_editcurve_regenerate_single(gps, from_start, from_end, error_threshold);
-
- memcpy(new_cpt_start, cpt_start, sizeof(bGPDcurve_point));
- memcpy(new_cpt_end, cpt_end, sizeof(bGPDcurve_point));
-}
-
static bool gpencil_dissolve_selected_curve_points(bGPdata *gpd,
bGPDframe *gpf,
bGPDstroke *gps,
- bGPDcurve *gpc,
eGP_DissolveMode mode,
const bool do_segments_refit,
const float error_threshold)
{
+ bGPDcurve *gpc = gps->editcurve;
if ((gpc->flag & GP_CURVE_SELECT) == 0) {
return false;
}
- int first = -1, last = 0;
- int num_points_remaining = gpc->tot_curve_points;
- const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC);
+ int num_points_remaining = gpc->tot_curve_points;
+ int old_num_points = gpc->tot_curve_points;
switch (mode) {
- case GP_DISSOLVE_POINTS:
- for (int i = 0; i < gpc->tot_curve_points; i++) {
- bGPDcurve_point *cpt = &gpc->curve_points[i];
- if (cpt->flag & GP_CURVE_POINT_SELECT) {
- num_points_remaining--;
- }
- else {
- if (first < 0) {
- first = i;
- }
- last = i;
- }
- }
+ case GP_DISSOLVE_POINTS: {
+ num_points_remaining = BKE_gpencil_editcurve_dissolve(
+ gps, GP_CURVE_POINT_SELECT, do_segments_refit, error_threshold);
break;
- case GP_DISSOLVE_BETWEEN:
+ }
+ case GP_DISSOLVE_BETWEEN: {
+ int first = -1, last = 0;
for (int i = 0; i < gpc->tot_curve_points; i++) {
bGPDcurve_point *cpt = &gpc->curve_points[i];
if (cpt->flag & GP_CURVE_POINT_SELECT) {
@@ -2366,24 +2337,27 @@ static bool gpencil_dissolve_selected_curve_points(bGPdata *gpd,
for (int i = first + 1; i < last; i++) {
bGPDcurve_point *cpt = &gpc->curve_points[i];
if ((cpt->flag & GP_CURVE_POINT_SELECT) == 0) {
- num_points_remaining--;
+ cpt->flag |= GP_CURVE_POINT_TAG;
}
}
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list