Commit: cd07dd2a1ce2d4b8f547afcae1adb66e28cd5cb1
Author: Antonioya
Date:   Sun Dec 30 13:35:29 2018 +0100
Branches: greasepencil-object
https://developer.blender.org/rBcd07dd2a1ce2d4b8f547afcae1adb66e28cd5cb1

GP: New Segment selection mode

New option to select points between stroke collision. This is useful to select 
the segment between two strokes to make merges.

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

M       source/blender/blenkernel/BKE_gpencil.h
M       source/blender/blenkernel/intern/gpencil.c
M       source/blender/editors/gpencil/gpencil_select.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/source/blender/blenkernel/BKE_gpencil.h 
b/source/blender/blenkernel/BKE_gpencil.h
index 989bec1957b..a5ca59a85e2 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -170,6 +170,10 @@ void BKE_gpencil_subdivide(struct bGPDstroke *gps, int 
level, int flag);
 
 void BKE_gpencil_stroke_2d_flat(
        const struct bGPDspoint *points, int totpoints, float(*points2d)[2], 
int *r_direction);
+void BKE_gpencil_stroke_2d_flat_ref(
+       const struct bGPDspoint *ref_points, int ref_totpoints,
+       const struct bGPDspoint *points, int totpoints,
+       float(*points2d)[2], int *r_direction);
 
 void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]);
 
diff --git a/source/blender/blenkernel/intern/gpencil.c 
b/source/blender/blenkernel/intern/gpencil.c
index d347e10921c..00a797f9846 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -1563,6 +1563,8 @@ int BKE_gpencil_get_material_index(Object *ob, Material 
*ma)
 /* Get points of stroke always flat to view not affected by camera view or 
view position */
 void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, 
float(*points2d)[2], int *r_direction)
 {
+       BLI_assert(totpoints >= 3);
+
        const bGPDspoint *pt0 = &points[0];
        const bGPDspoint *pt1 = &points[1];
        const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
@@ -1604,3 +1606,53 @@ void BKE_gpencil_stroke_2d_flat(const bGPDspoint 
*points, int totpoints, float(*
        *r_direction = (int)locy[2];
 }
 
+/* Get points of stroke always flat to view not affected by camera view or 
view position
+ * using another stroke as reference
+ */
+void BKE_gpencil_stroke_2d_flat_ref(
+       const bGPDspoint *ref_points, int ref_totpoints,
+       const bGPDspoint *points, int totpoints,
+       float(*points2d)[2], int *r_direction)
+{
+       BLI_assert(ref_totpoints >= 3);
+
+       const bGPDspoint *pt0 = &ref_points[0];
+       const bGPDspoint *pt1 = &ref_points[1];
+       const bGPDspoint *pt3 = &ref_points[(int)(ref_totpoints * 0.75)];
+
+       float locx[3];
+       float locy[3];
+       float loc3[3];
+       float normal[3];
+
+       /* local X axis (p0 -> p1) */
+       sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+       /* point vector at 3/4 */
+       sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+       /* vector orthogonal to polygon plane */
+       cross_v3_v3v3(normal, locx, loc3);
+
+       /* local Y axis (cross to normal/x axis) */
+       cross_v3_v3v3(locy, normal, locx);
+
+       /* Normalize vectors */
+       normalize_v3(locx);
+       normalize_v3(locy);
+
+       /* Get all points in local space */
+       for (int i = 0; i < totpoints; i++) {
+               const bGPDspoint *pt = &points[i];
+               float loc[3];
+
+               /* Get local space using first point as origin (ref stroke) */
+               sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+               points2d[i][0] = dot_v3v3(loc, locx);
+               points2d[i][1] = dot_v3v3(loc, locy);
+       }
+
+       /* Concave (-1), Convex (1), or Autodetect (0)? */
+       *r_direction = (int)locy[2];
+}
diff --git a/source/blender/editors/gpencil/gpencil_select.c 
b/source/blender/editors/gpencil/gpencil_select.c
index fff753cf3a9..a92e6526b34 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -861,6 +861,7 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
  *       It would be great to de-duplicate the logic here sometime, but that 
can wait...
  */
 static bool gp_stroke_do_circle_sel(
+               bGPdata *gpd, bGPDlayer *gpl,
         bGPDstroke *gps, GP_SpaceConversion *gsc,
         const int mx, const int my, const int radius,
         const bool select, rcti *rect, float diff_mat[4][4], const int 
selectmode)
@@ -958,6 +959,14 @@ static bool gp_stroke_do_circle_sel(
                        }
                }
 
+               /* expand selection to segment */
+               if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select)) 
{
+                       float r_hita[3], r_hitb[3];
+                       bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
+                       ED_gpencil_select_stroke_segment(
+                               gpd, gpl, gps, pt1, hit_select, r_hita, r_hitb);
+               }
+
                /* Ensure that stroke selection is in sync with its points */
                BKE_gpencil_stroke_sync_selection(gps);
        }
@@ -1012,7 +1021,8 @@ static int gpencil_circle_select_exec(bContext *C, 
wmOperator *op)
        GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
        {
                changed |= gp_stroke_do_circle_sel(
-                       gps, &gsc, mx, my, radius, select, &rect, 
gpstroke_iter.diff_mat, selectmode);
+                       gpd, gpl, gps, &gsc, mx, my, radius, select, &rect,
+                       gpstroke_iter.diff_mat, selectmode);
        }
        GP_EDITABLE_STROKES_END(gpstroke_iter);
 
@@ -1074,6 +1084,9 @@ static int gpencil_generic_select_exec(
        const bool strokemode = (
                (ts->gpencil_selectmode == GP_SELECTMODE_STROKE) &&
                ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
+       const bool segmentmode = (
+                       (ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) &&
+                       ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
        const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
 
 
@@ -1124,6 +1137,17 @@ static int gpencil_generic_select_exec(
                                if (sel_op_result != -1) {
                                        SET_FLAG_FROM_TEST(pt->flag, 
sel_op_result, GP_SPOINT_SELECT);
                                        changed = true;
+
+                                       /* expand selection to segment */
+                                       if ((sel_op_result != -1) &&
+                                               (segmentmode))
+                                       {
+                                               bool hit_select = 
(bool)(pt->flag & GP_SPOINT_SELECT);
+                                               float r_hita[3], r_hitb[3];
+                                               
ED_gpencil_select_stroke_segment(
+                                                       gpd, gpl, gps, pt, 
hit_select, r_hita, r_hitb);
+                                       }
+
                                }
                        }
                        else {
@@ -1350,6 +1374,7 @@ static int gpencil_select_exec(bContext *C, wmOperator 
*op)
 
        GP_SpaceConversion gsc = {NULL};
 
+       bGPDlayer *hit_layer = NULL;
        bGPDstroke *hit_stroke = NULL;
        bGPDspoint *hit_point = NULL;
        int hit_distance = radius_squared;
@@ -1394,6 +1419,7 @@ static int gpencil_select_exec(bContext *C, wmOperator 
*op)
                                if (pt_distance <= radius_squared) {
                                        /* only use this point if it is a 
better match than the current hit - T44685 */
                                        if (pt_distance < hit_distance) {
+                                               hit_layer = gpl;
                                                hit_stroke = gps;
                                                hit_point = pt;
                                                hit_distance = pt_distance;
@@ -1454,6 +1480,14 @@ static int gpencil_select_exec(bContext *C, wmOperator 
*op)
                        /* we're adding selection, so selection must be true */
                        hit_point->flag  |= GP_SPOINT_SELECT;
                        hit_stroke->flag |= GP_STROKE_SELECT;
+
+                       /* expand selection to segment */
+                       if (ts->gpencil_selectmode == GP_SELECTMODE_SEGMENT) {
+                               float r_hita[3], r_hitb[3];
+                               bool hit_select = (bool)(hit_point->flag & 
GP_SPOINT_SELECT);
+                               ED_gpencil_select_stroke_segment(
+                                               gpd, hit_layer, hit_stroke, 
hit_point, hit_select, r_hita, r_hitb);
+                       }
                }
                else {
                        /* deselect point */
diff --git a/source/blender/editors/gpencil/gpencil_utils.c 
b/source/blender/editors/gpencil/gpencil_utils.c
index 4d6a7b547c6..bc3ac0fb056 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -36,6 +36,7 @@
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
+#include "BLI_ghash.h"
 #include "BLI_utildefines.h"
 #include "BLT_translation.h"
 #include "BLI_rand.h"
@@ -1947,4 +1948,209 @@ void ED_gpencil_update_color_uv(Main *bmain, Material 
*mat)
                }
        }
 }
-/* ******************************************************** */
+
+static bool gpencil_check_collision(
+       bGPDstroke *gps, bGPDstroke **gps_array, GHash *all_2d,
+       int totstrokes, float p2d_a1[2], float p2d_a2[2], float r_hit[2])
+{
+       bool hit = false;
+       /* check segment with all segments of all strokes */
+       for (int s = 0; s < totstrokes; s++) {
+               bGPDstroke *gps_iter = gps_array[s];
+               if (gps_iter->totpoints < 3) {
+                       continue;
+               }
+               /* get stroke 2d version */
+               float(*points2d)[2] = BLI_ghash_lookup(all_2d, gps_iter);
+
+               for (int i2 = 0; i2 < gps_iter->totpoints - 1; i2++) {
+                       float p2d_b1[2], p2d_b2[2];
+                       copy_v2_v2(p2d_b1, points2d[i2]);
+                       copy_v2_v2(p2d_b2, points2d[i2 + 1]);
+
+                       /* check collision */
+                       int check = isect_seg_seg_v2_point(p2d_a1, p2d_a2, 
p2d_b1, p2d_b2, r_hit);
+                       if (check > 0) {
+                               hit = true;
+                               break;
+                       }
+               }
+
+               if (hit) {
+                       break;
+               }
+       }
+
+       if (!hit) {
+               zero_v2(r_hit);
+       }
+
+       return hit;
+}
+
+/* extend selection to stroke intersections */
+int ED_gpencil_select_stroke_segment(
+       bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *pt, bool 
select,
+       float r_hita[3], float r_hitb[3])
+{
+       bGPDspoint *pta1 = NULL;
+       bGPDspoint *pta2 = NULL;
+
+       bGPDframe *gpf = gpl->actframe;
+       if (gpf == NULL) {
+               return 0;
+       }
+
+       int memsize = BLI_listbase_count(&gpf->strokes) - 1;
+       bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * memsize, 
__func__);
+
+       /* Save strokes with possible collision. This reduces the time to check 
the
+        * points of contact because some strokes could be outside of the 
possible
+        * collision areas.
+        */
+       int totstrokes = 0;
+       for (bGPDstroke *gps_iter = gpf->strokes.first; gps_iter; gps_iter = 
gps_iter->next) {
+               /* do not check selfcollision */
+               if ((gps == gps_iter) || (gps_iter->totpoints < 3)) {
+                       continue;
+               }
+               gps_array[totstrokes] = gps_iter;
+               totstrokes++;
+       }
+
+       if (totstrokes == 0) {
+               return 0;
+       }
+
+       /* look for index of the current point */
+       int cur_idx = -1;
+       for (int i = 0; i < gps->totpoints; i++) {
+               pta1 = &gps->points[i];
+               if (pta1 == pt) {
+                       cur_idx = i;
+                       break;
+               }
+       }
+       if (cur_idx < 0) {
+               return 0;
+       }
+
+       /* convert all gps points to 2d and save in a hash to avoid 
recalculation  */
+       int direction = 0;
+       float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, 
"GP Stroke temp 2d points");
+       BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, 
&direction);
+
+       GHash *all_2d = BLI_ghash_ptr_new(__func__);
+
+       for (int s = 0; s < totstrokes; s++) {
+               bGPDstroke *gps_iter = gps_array[s];
+               float(*points2d_iter)[2] = MEM_mallocN(sizeof(*points2d_iter) * 
gps_iter->totpoints, __func__);
+               BKE_gpencil_stroke_2d_flat_ref(
+                       gps->points, gps->totpoints,
+                       gps_iter->points, gps_iter->totpoints, points2d_iter, 
&direction);
+               BLI_ghash_insert(all_2d, gps_iter, points2d_iter);
+       }
+
+       bool hit_a = false;
+       bool hit_b = false;
+       float dist1 = 0.0f;
+       float dist2 = 0.0f;
+       float f = 0.0f;
+       float r_hit2d[2];
+
+       /* analyze points before current */
+       if (cur_idx > 0) {
+               for (int i 

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to