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
This commit is contained in:
parent
bb3a538843
commit
52b7f2b089
Notes:
blender-bot
2023-02-14 11:25:11 +01:00
Referenced by issue #99443, Box selection in uv editor does not work as expected with edge mode
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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)};
|
||||
|
|
|
@ -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(
|
||||
®ion->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);
|
||||
|
|
Loading…
Reference in New Issue