Commit: 274c8ae9e27a7ba5290c72c72cbc2fcdb6d7b056
Author: Falk David
Date:   Mon Aug 24 15:23:36 2020 +0200
Branches: soc-2020-greasepencil-curve
https://developer.blender.org/rB274c8ae9e27a7ba5290c72c72cbc2fcdb6d7b056

GPencil: Handle strokes with one or two points

Generating the curve for a stroke with one or two strokes could
crash because it was not handled properly.

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

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

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

diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h 
b/source/blender/blenkernel/BKE_gpencil_curve.h
index 3c52b67dfdc..e8c4139384f 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -44,10 +44,11 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
 
 struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
                                                         const float 
error_threshold,
-                                                        const float 
corner_angle);
-void BKE_gpencil_stroke_editcurve_update(struct bGPDstroke *gps,
-                                         const float error_threshold,
-                                         const float corner_angle);
+                                                        const float 
corner_angle,
+                                                        const float 
stroke_radius);
+void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
+                                         struct bGPDlayer *gpl,
+                                         struct bGPDstroke *gps);
 void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPDstroke *gps, 
struct bGPDcurve *gpc);
 void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPDstroke *gps, 
struct bGPDcurve *gpc);
 void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c 
b/source/blender/blenkernel/intern/gpencil_curve.c
index 0ae6fb6a267..0b4a438c67d 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -563,26 +563,25 @@ void BKE_gpencil_convert_curve(Main *bmain,
 /** \name Editcurve kernel functions
  * \{ */
 
-/**
- * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil 
stroke points.
- */
-bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
-                                                 const float error_threshold,
-                                                 const float corner_angle)
+static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps,
+                                                              const float 
stroke_radius)
 {
-  if (gps->totpoints < 1) {
-    return NULL;
-  }
-  else if (gps->totpoints == 1) {
+  BLI_assert(gps->totpoints < 3);
+
+  if (gps->totpoints == 1) {
     bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(1);
     bGPDspoint *pt = &gps->points[0];
     bGPDcurve_point *cpt = &editcurve->curve_points[0];
     BezTriple *bezt = &cpt->bezt;
 
+    /* Handles are twice as long as the radius of the point. */
+    float offset = (pt->pressure * stroke_radius) * 2.0f;
+
     float tmp_vec[3];
     for (int j = 0; j < 3; j++) {
       copy_v3_v3(tmp_vec, &pt->x);
-      tmp_vec[0] += (j - 1);
+      /* Move handles along the x-axis away from the control point */
+      tmp_vec[0] += (float)(j - 1) * offset;
       copy_v3_v3(bezt->vec[j], tmp_vec);
     }
 
@@ -591,13 +590,63 @@ bGPDcurve 
*BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
     copy_v4_v4(cpt->vert_color, pt->vert_color);
 
     /* default handle type */
-    bezt->h1 = HD_ALIGN;
-    bezt->h2 = HD_ALIGN;
+    bezt->h1 = HD_FREE;
+    bezt->h2 = HD_FREE;
 
     cpt->point_index = 0;
 
     return editcurve;
   }
+  if (gps->totpoints == 2) {
+    bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(2);
+    bGPDspoint *first_pt = &gps->points[0];
+    bGPDspoint *last_pt = &gps->points[1];
+
+    float length = len_v3v3(&first_pt->x, &last_pt->x);
+    float offset = length / 3;
+    float dir[3];
+    sub_v3_v3v3(dir, &last_pt->x, &first_pt->x);
+
+    for (int i = 0; i < 2; i++) {
+      bGPDspoint *pt = &gps->points[i];
+      bGPDcurve_point *cpt = &editcurve->curve_points[i];
+      BezTriple *bezt = &cpt->bezt;
+
+      float tmp_vec[3];
+      for (int j = 0; j < 3; j++) {
+        copy_v3_v3(tmp_vec, dir);
+        normalize_v3_length(tmp_vec, (float)(j - 1) * offset);
+        add_v3_v3v3(bezt->vec[j], &pt->x, tmp_vec);
+      }
+
+      cpt->pressure = pt->pressure;
+      cpt->strength = pt->strength;
+      copy_v4_v4(cpt->vert_color, pt->vert_color);
+
+      /* default handle type */
+      bezt->h1 = HD_VECT;
+      bezt->h2 = HD_VECT;
+
+      cpt->point_index = 0;
+    }
+
+    return editcurve;
+  }
+
+  return NULL;
+}
+
+/**
+ * Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil 
stroke points.
+ */
+bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
+                                                 const float error_threshold,
+                                                 const float corner_angle,
+                                                 const float stroke_radius)
+{
+  if (gps->totpoints < 3) {
+    return gpencil_stroke_editcurve_generate_edgecases(gps, stroke_radius);
+  }
 #define POINT_DIM 9
 
   float *points = MEM_callocN(sizeof(float) * gps->totpoints * POINT_DIM, 
__func__);
@@ -704,9 +753,7 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke 
*gps,
 /**
  * Updates the editcurve for a stroke. Frees the old curve if one exists and 
generates a new one.
  */
-void BKE_gpencil_stroke_editcurve_update(bGPDstroke *gps,
-                                         const float error_threshold,
-                                         const float corner_angle)
+void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, 
bGPDstroke *gps)
 {
   if (gps == NULL || gps->totpoints < 0) {
     return;
@@ -716,7 +763,11 @@ void BKE_gpencil_stroke_editcurve_update(bGPDstroke *gps,
     BKE_gpencil_free_stroke_editcurve(gps);
   }
 
-  bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_generate(gps, 
error_threshold, corner_angle);
+  float defaultpixsize = 1000.0f / gpd->pixfactor;
+  float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) 
/ 2.0f;
+
+  bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_generate(
+      gps, gpd->curve_edit_threshold, gpd->curve_corner_angle, stroke_radius);
   if (editcurve == NULL) {
     return;
   }
@@ -1012,7 +1063,8 @@ void 
BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
   if (curve_point_array_len == 0) {
     return;
   }
-  else if (curve_point_array_len == 1) {
+  /* Handle case for single curve point. */
+  if (curve_point_array_len == 1) {
     bGPDcurve_point *cpt = &curve_point_array[0];
     /* resize stroke point array */
     gps->totpoints = 1;
@@ -1022,7 +1074,7 @@ void 
BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
     }
 
     bGPDspoint *pt = &gps->points[0];
-    copy_v3_v3(&pt->x, cpt->bezt.vec[0]);
+    copy_v3_v3(&pt->x, cpt->bezt.vec[1]);
 
     pt->pressure = cpt->pressure;
     pt->strength = cpt->strength;
@@ -1095,7 +1147,8 @@ void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke 
*gps)
   }
 
   if (gpc->tot_curve_points == 1) {
-    BKE_nurb_handle_calc(&(gpc->curve_points[0].bezt), NULL, NULL, false, 0);
+    BKE_nurb_handle_calc(
+        &(gpc->curve_points[0].bezt), NULL, &(gpc->curve_points[0].bezt), 
false, 0);
     gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
   }
 
@@ -1307,16 +1360,14 @@ void 
BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd)
 
           /* Generate the curve if there is none or the stroke was changed */
           if (gps->editcurve == NULL) {
-            BKE_gpencil_stroke_editcurve_update(
-                gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+            BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
             /* Continue if curve could not be generated. */
             if (gps->editcurve == NULL) {
               continue;
             }
           }
           else if (gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
-            BKE_gpencil_stroke_editcurve_update(
-                gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+            BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
           }
           /* Update the selection from the stroke to the curve. */
           BKE_gpencil_editcurve_stroke_sync_selection(gps, gps->editcurve);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c 
b/source/blender/editors/gpencil/gpencil_edit.c
index 5f845a85fa6..f1b66b2c2a6 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -209,8 +209,7 @@ static int gpencil_editmode_toggle_exec(bContext *C, 
wmOperator *op)
     GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
     {
       if (gpc->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
-        BKE_gpencil_stroke_editcurve_update(
-            gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+        BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
         /* Update the selection from the stroke to the curve. */
         BKE_gpencil_editcurve_stroke_sync_selection(gps, gps->editcurve);
 
@@ -1194,7 +1193,7 @@ static void gpencil_curve_extrude_points(bGPdata *gpd,
 {
   const int old_num_points = gpc->tot_curve_points;
   const bool first_select = gpc->curve_points[0].flag & GP_CURVE_POINT_SELECT;
-  const bool last_select = gpc->curve_points[old_num_points - 1].flag & 
GP_CURVE_POINT_SELECT;
+  bool last_select = gpc->curve_points[old_num_points - 1].flag & 
GP_CURVE_POINT_SELECT;
 
   /* iterate over middle points */
   for (int i = 1; i < gpc->tot_curve_points - 1; i++) {
@@ -1231,6 +1230,11 @@ static void gpencil_curve_extrude_points(bGPdata *gpd,
     }
   }
 
+  /* Edgcase for single curve point. */
+  if (gpc->tot_curve_points == 1) {
+    last_select = false;
+  }
+
   if (first_select || last_select) {
     int new_num_points = old_num_points;
 
@@ -4237,8 +4241,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, 
wmOperator *op)
       ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf_, gps, mode, 
keep_original);
 
       if (is_curve_edit && gps->editcurve != NULL) {
-        BKE_gpencil_stroke_editcurve_update(
-            gps, gpd->curve_edit_threshold, gpd->curve_corner_angle);
+        BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
         /* Update the selection from the strok

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to