[Bf-blender-cvs] [cd07dd2a1ce] greasepencil-object: GP: New Segment selection mode

Antonioya noreply at git.blender.org
Sun Dec 30 22:16:11 CET 2018


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. @@



More information about the Bf-blender-cvs mailing list