Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiddhartha Jejurkar <f20180617@goa.bits-pilani.ac.in>2022-07-12 12:39:57 +0300
committerCampbell Barton <campbell@blender.org>2022-07-12 12:50:40 +0300
commit52b7f2b089071a6d2281e369ab820c9406e06c4e (patch)
treecc9755e740388cfc38a30a92cd303222d5fc69ae /source/blender
parentbb3a53884394908ba34459c38d419e6c4abe6107 (diff)
UV: Box and lasso selection for partially intersecting edges
In UV edge mode, box and lasso selections allow edge selections only when the entire edge is contained within the selection area. This doesn't consider any edges that partially overlap with the selection area. This is now fixed by adding a second pass, similar to how these operators work for edit-mesh selections. Now if both operators are unable to find any edges contained within the selection area, then they will perform a second pass which checks for edges that partially intersect with the selection area. Now edge selection in the UV editor matches edit-mesh edge-selection when drawing wire-frame. Resolves T99443. Ref D15362
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/include/UI_view2d.h6
-rw-r--r--source/blender/editors/interface/view2d.cc35
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c69
3 files changed, 110 insertions, 0 deletions
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 5c4eb254462..e508c96b4f1 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -309,6 +309,12 @@ float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
bool UI_view2d_view_to_region_clip(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+bool UI_view2d_view_to_region_segment_clip(const View2D *v2d,
+ const float xy_a[2],
+ const float xy_b[2],
+ int r_region_a[2],
+ int r_region_b[2]) ATTR_NONNULL();
+
/**
* Convert from 2d-view space to screen/region space
*
diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc
index ee4bfd351ae..1bf7e25b154 100644
--- a/source/blender/editors/interface/view2d.cc
+++ b/source/blender/editors/interface/view2d.cc
@@ -1695,6 +1695,41 @@ void UI_view2d_view_to_region_fl(
*r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask));
}
+bool UI_view2d_view_to_region_segment_clip(const View2D *v2d,
+ const float xy_a[2],
+ const float xy_b[2],
+ int r_region_a[2],
+ int r_region_b[2])
+{
+ rctf rect_unit;
+ rect_unit.xmin = rect_unit.ymin = 0.0f;
+ rect_unit.xmax = rect_unit.ymax = 1.0f;
+
+ /* Express given coordinates as proportional values. */
+ const float s_a[2] = {
+ (xy_a[0] - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur),
+ (xy_a[1] - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur),
+ };
+ const float s_b[2] = {
+ (xy_b[0] - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur),
+ (xy_b[1] - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur),
+ };
+
+ /* Set initial value in case coordinates lie outside bounds. */
+ r_region_a[0] = r_region_b[0] = r_region_a[1] = r_region_b[1] = V2D_IS_CLIPPED;
+
+ if (BLI_rctf_isect_segment(&rect_unit, s_a, s_b)) {
+ r_region_a[0] = (int)(v2d->mask.xmin + (s_a[0] * BLI_rcti_size_x(&v2d->mask)));
+ r_region_a[1] = (int)(v2d->mask.ymin + (s_a[1] * BLI_rcti_size_y(&v2d->mask)));
+ r_region_b[0] = (int)(v2d->mask.xmin + (s_b[0] * BLI_rcti_size_x(&v2d->mask)));
+ r_region_b[1] = (int)(v2d->mask.ymin + (s_b[1] * BLI_rcti_size_y(&v2d->mask)));
+
+ return true;
+ }
+
+ return false;
+}
+
void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index db834f6a0fd..b5a564fd984 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -3582,6 +3582,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
}
}
else if (use_edge && !pinned) {
+ bool do_second_pass = true;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
@@ -3596,11 +3597,35 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
uvedit_edge_select_set_with_sticky(
scene, em, l_prev, select, false, cd_loop_uv_offset);
changed = true;
+ do_second_pass = false;
}
l_prev = l;
luv_prev = luv;
}
}
+ /* Do a second pass if no complete edges could be selected.
+ * This matches wire-frame edit-mesh selection in the 3D view. */
+ if (do_second_pass) {
+ /* Second pass to check if edges partially overlap with the selection area (box). */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (BLI_rctf_isect_segment(&rectf, luv_prev->uv, luv->uv)) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ l_prev = l;
+ luv_prev = luv;
+ }
+ }
+ }
}
else {
/* other selection modes */
@@ -3920,6 +3945,24 @@ static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region,
return false;
}
+static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region,
+ const rcti *clip_rect,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const float co_test_a[2],
+ const float co_test_b[2])
+{
+ int co_screen_a[2], co_screen_b[2];
+ if (UI_view2d_view_to_region_segment_clip(
+ &region->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
+ BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
+ BLI_lasso_is_edge_inside(
+ mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) {
+ return true;
+ }
+ return false;
+}
+
static bool do_lasso_select_mesh_uv(bContext *C,
const int mcoords[][2],
const int mcoords_len,
@@ -3988,6 +4031,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
}
}
else if (use_edge) {
+ bool do_second_pass = true;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
@@ -4004,12 +4048,37 @@ static bool do_lasso_select_mesh_uv(bContext *C,
region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
uvedit_edge_select_set_with_sticky(
scene, em, l_prev, select, false, cd_loop_uv_offset);
+ do_second_pass = false;
changed = true;
}
l_prev = l;
luv_prev = luv;
}
}
+ /* Do a second pass if no complete edges could be selected.
+ * This matches wire-frame edit-mesh selection in the 3D view. */
+ if (do_second_pass) {
+ /* Second pass to check if edges partially overlap with the selection area (lasso). */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_edge_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv, luv_prev->uv)) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ l_prev = l;
+ luv_prev = luv;
+ }
+ }
+ }
}
else { /* Vert Selection. */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);