[Bf-blender-cvs] [dc8eb553903] greasepencil-object: GP: Basic Lasso Cutter support

Antonioya noreply at git.blender.org
Wed Jan 2 19:40:40 CET 2019


Commit: dc8eb553903f54401b39b17f7061944de72bc560
Author: Antonioya
Date:   Wed Jan 2 19:03:23 2019 +0100
Branches: greasepencil-object
https://developer.blender.org/rBdc8eb553903f54401b39b17f7061944de72bc560

GP: Basic Lasso Cutter support

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

M	source/blender/editors/gpencil/gpencil_edit.c

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

diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 05a8df0e638..393f15608eb 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -40,6 +40,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_ghash.h"
+#include "BLI_lasso_2d.h"
 #include "BLI_math.h"
 #include "BLI_string.h"
 #include "BLI_string_utils.h"
@@ -86,6 +87,7 @@
 #include "ED_object.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
+#include "ED_select_utils.h"
 #include "ED_space_api.h"
 
 #include "DEG_depsgraph.h"
@@ -3709,39 +3711,84 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
 	RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
 }
 
-/* smart stroke knife */
-static bool gpencil_cutter_poll(bContext *C)
+/* smart stroke cutter for trimming stroke ends */
+struct GP_SelectLassoUserData {
+	rcti rect;
+	const int(*mcords)[2];
+	int         mcords_len;
+};
+
+static bool gpencil_test_lasso(
+	bGPDstroke *gps, bGPDspoint *pt,
+	const GP_SpaceConversion *gsc, const float diff_mat[4][4],
+	void *user_data)
 {
-	bGPdata *gpd = ED_gpencil_data_get_active(C);
+	const struct GP_SelectLassoUserData *data = user_data;
+	bGPDspoint pt2;
+	int x0, y0;
+	gp_point_to_parent_space(pt, diff_mat, &pt2);
+	gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
+	/* test if in lasso */
+	return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) &&
+		BLI_rcti_isect_pt(&data->rect, x0, y0) &&
+		BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+}
 
-	if (GPENCIL_PAINT_MODE(gpd)) {
-		if (gpd->layers.first)
-			return true;
+typedef bool(*GPencilTestFn)(
+	bGPDstroke *gps, bGPDspoint *pt,
+	const GP_SpaceConversion *gsc, const float diff_mat[4][4], void *user_data);
+
+void gpencil_cutter_dissolve(bGPdata *gpd, bGPDlayer *hit_layer, bGPDstroke *hit_stroke, bGPDspoint *hit_point)
+{
+	bGPDspoint *pt = NULL;
+	bGPDspoint *pt1 = NULL;
+	int i;
+
+	bGPDstroke *gpsn = hit_stroke->next;
+
+	/* if only one point delete */
+	if ((hit_stroke) && (hit_stroke->totpoints == 1)) {
+		BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
+		BKE_gpencil_free_stroke(hit_stroke);
+		hit_stroke = NULL;
 	}
 
-	return false;
+	/* if very small distance delete */
+	if ((hit_stroke) && (hit_stroke->totpoints == 2)) {
+		pt = &hit_stroke->points[0];
+		pt1 = &hit_stroke->points[1];
+		if (len_v3v3(&pt->x, &pt1->x) < 0.001f) {
+			BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
+			BKE_gpencil_free_stroke(hit_stroke);
+			hit_stroke = NULL;
+		}
+	}
+
+	if (hit_stroke) {
+		/* tag and dissolve */
+		for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
+			if (pt->flag & GP_SPOINT_SELECT) {
+				pt->flag &= ~GP_SPOINT_SELECT;
+				pt->flag |= GP_SPOINT_TAG;
+			}
+		}
+		gp_stroke_delete_tagged_points(
+			hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
+	}
 }
 
-static int gpencil_cutter_exec(bContext *C, wmOperator *op)
+static int gpencil_cutter_lasso_select(
+	bContext *C, wmOperator *op,
+	GPencilTestFn is_inside_fn, void *user_data)
 {
-	ScrArea *sa = CTX_wm_area(C);
 	bGPdata *gpd = ED_gpencil_data_get_active(C);
+	ScrArea *sa = CTX_wm_area(C);
 
-	/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
-	const float radius = 0.50f * U.widget_unit;
-	const int radius_squared = (int)(radius * radius);
-
-	int mval[2] = { 0 };
-
+	bGPDspoint *pt;
+	int i;
 	GP_SpaceConversion gsc = { NULL };
 
-	bGPDlayer *hit_layer = NULL;
-	bGPDstroke *hit_stroke = NULL;
-	bGPDspoint *hit_point = NULL;
-	bGPDspoint *pt = NULL;
-	bGPDspoint *pt1 = NULL;
-	int i = 0;
-	int hit_distance = radius_squared;
+	bool changed = false;
 
 	/* sanity checks */
 	if (sa == NULL) {
@@ -3752,98 +3799,60 @@ static int gpencil_cutter_exec(bContext *C, wmOperator *op)
 	/* init space conversion stuff */
 	gp_point_conversion_init(C, &gsc);
 
-	/* get mouse location */
-	RNA_int_get_array(op->ptr, "location", mval);
-
-	/* Find stroke point which gets hit */
-	GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+	/* deselect all strokes first */
+	CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
 	{
-		/* deselect stroke */
-		gps->flag &= ~GP_STROKE_SELECT;
+		bGPDspoint *pt;
+		int i;
 
-		/* firstly, check for hit-point */
 		for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
-			int xy[2];
-			/* deselect point */
 			pt->flag &= ~GP_SPOINT_SELECT;
-
-			bGPDspoint pt2;
-			gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
-			gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]);
-
-			/* do boundbox check first */
-			if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) {
-				const int pt_distance = len_manhattan_v2v2_int(mval, xy);
-
-				/* check if point is inside */
-				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;
-					}
-				}
-			}
 		}
-	}
-	GP_EDITABLE_STROKES_END(gpstroke_iter);
 
-	/* if no stroke point selected or null data, exit */
-	if (ELEM(NULL, hit_layer, hit_layer->actframe, hit_stroke, hit_point)) {
-		return OPERATOR_CANCELLED;
-	}
-
-	bGPDstroke *gpsn = hit_stroke->next;
-
-	/* if only one point delete */
-	if ((hit_stroke) && (hit_stroke->totpoints == 1)) {
-		BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
-		BKE_gpencil_free_stroke(hit_stroke);
-		hit_stroke = NULL;
+		gps->flag &= ~GP_STROKE_SELECT;
 	}
+	CTX_DATA_END;
 
-	/* if very small distance delete */
- 	if ((hit_stroke) && (hit_stroke->totpoints == 2)) {
-		pt = &hit_stroke->points[0];
-		pt1 = &hit_stroke->points[1];
-		if (len_v3v3(&pt->x, &pt1->x) < 0.001f) {
-			BLI_remlink(&hit_layer->actframe->strokes, hit_stroke);
-			BKE_gpencil_free_stroke(hit_stroke);
-			hit_stroke = NULL;
+	/* select points */
+	GP_EDITABLE_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+	{
+		for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+			/* convert point coords to screenspace */
+			const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
+			if (is_inside) {
+				changed = true;
+				pt->flag |= GP_SPOINT_SELECT;
+				gps->flag |= GP_STROKE_SELECT;
+			}
 		}
 	}
+	GP_EDITABLE_STROKES_END(gpstroke_iter);
 
-	if (hit_stroke) {
-		/* select segment */
-		hit_point->flag &= ~GP_SPOINT_SELECT;
-		hit_stroke->flag &= ~GP_STROKE_SELECT;
-		float r_hita[3], r_hitb[3];
-		int hit = ED_gpencil_select_stroke_segment(
-			gpd, hit_layer, hit_stroke, hit_point,
-			true, true, r_hita, r_hitb);
-		/* tag and dissolve */
-		if (hit > 0) {
-			/* deselect points and tag  */
-			for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
-				if (pt->flag & GP_SPOINT_SELECT) {
-					pt->flag &= ~GP_SPOINT_SELECT;
-					pt->flag |= GP_SPOINT_TAG;
+	/* expand selection and delete */
+	bGPDstroke *gpsn;
+	for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+		bGPDframe *gpf = gpl->actframe;
+		for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gpsn) {
+			gpsn = gps->next;
+			if (gps->flag & GP_STROKE_SELECT) {
+				for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+					if (pt->flag & GP_SPOINT_SELECT) {
+						/* expand selection to segment */
+						float r_hita[3], r_hitb[3];
+						int hit = ED_gpencil_select_stroke_segment(
+							gpd, gpl, gps, pt, true, true, r_hita, r_hitb);
+						if (hit > 0) {
+							gpencil_cutter_dissolve(gpd, gpl, gps, pt);
+						}
+					}
 				}
 			}
-			gp_stroke_delete_tagged_points(
-				hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1);
 		}
 	}
 
 	/* updates */
-	if (hit_point != NULL) {
-		DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
-
-		/* copy on write tag is needed, or else no refresh happens */
-		DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
-
+	if (changed) {
+		DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
 		WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
 		WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
 	}
@@ -3851,32 +3860,62 @@ static int gpencil_cutter_exec(bContext *C, wmOperator *op)
 	return OPERATOR_FINISHED;
 }
 
-static int gpencil_cutter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static bool gpencil_cutter_poll(bContext *C)
 {
-	RNA_int_set_array(op->ptr, "location", event->mval);
-	return gpencil_cutter_exec(C, op);
+	bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+	if (GPENCIL_PAINT_MODE(gpd)) {
+		if (gpd->layers.first)
+			return true;
+	}
+
+	return false;
 }
 
-void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
+static int gpencil_cutter_exec(bContext *C, wmOperator *op)
 {
-	PropertyRNA *prop;
+	ScrArea *sa = CTX_wm_area(C);
+	/* sanity checks */
+	if (sa == NULL) {
+		BKE_report(op->reports, RPT_ERROR, "No active area");
+		return OPERATOR_CANCELLED;
+	}
+
+	struct GP_SelectLassoUserData data = { 0 };
+	data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+
+	/* Sanity check. */
+	if (data.mcords == NULL) {
+		return OPERATOR_PASS_THROUGH;
+	}
+
+	/* Compute boundbox of lasso (for faster testing later). */
+	BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+
+	gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data);
 
+	MEM_freeN((void *)data.mcords);
+
+	return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
+{
 	/* identifiers */
 	ot->name = "Stroke Cutter";
 	ot->description = "Select section and cut";
 	ot->idname = "GPENCIL_OT_stroke_cutter";
 
 	/* callbacks */
-	ot->invoke = gpencil_cutter_invoke;
+	ot->invoke = WM_gesture_lasso_invoke;
+	ot->modal = WM_gesture_lasso_modal;
 	ot->exec = gpencil_cutter_exec;
 	ot->poll = gpencil_cutter_poll;
+	ot->cancel = WM_gesture_lasso_cancel;
 
 	/* flag */
 	ot->flag = OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
 
 	/* properties */
-	WM_operator_properties_mouse_select(ot);
-
-	prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
-	RNA_def_property_flag(prop, PROP_HIDDEN);
+	WM_operator_properties_gesture_lasso(ot);


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list