[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