diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-01-09 10:27:25 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-01-09 10:42:36 +0300 |
commit | 246efd7286f6187e4dd4b3edcc79cccb1746bb1d (patch) | |
tree | e2fd2e8c3ebc7033a913ca6cf41eff386ca1e7d0 /source | |
parent | 645298be29601b0e772a15fe04c570a31df4a25d (diff) |
Fix UV selection threshold which ignored image aspect and zoom level
Selecting UVs wasn't properly scaling based on the zoom or image aspect.
This now matches vertex selection in the 3D view.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_uv.c | 2 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_intern.h | 26 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 22 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_path.c | 8 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_select.c | 73 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_smart_stitch.c | 2 |
6 files changed, 64 insertions, 69 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index f77d473ae57..219a8303674 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -543,7 +543,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm /* we need to find the active island here */ if (do_island_optimization) { UvElement *element; - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit); element = BM_uv_element_get(data->elementMap, hit.efa, hit.l); diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 28567234fab..6fef7ebcf22 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -41,13 +41,34 @@ typedef struct UvNearestHit { /** Always set if we have a hit. */ struct BMFace *efa; struct BMLoop *l; - /** Needs to be set before calling nearest functions. */ + /** + * Needs to be set before calling nearest functions. + * + * \note When #UV_NEAREST_HIT_INIT_DIST_PX or #UV_NEAREST_HIT_INIT_MAX are used, + * this value is pixels squared. + */ float dist_sq; + + /** Scale the UV's to account for aspect ratio from the image view. */ + float scale[2]; } UvNearestHit; -#define UV_NEAREST_HIT_INIT \ +#define UV_NEAREST_HIT_INIT_DIST_PX(v2d, dist_px) \ + { \ + .dist_sq = square_f(U.pixelsize * dist_px), \ + .scale = { \ + UI_view2d_scale_get_x(v2d), \ + UI_view2d_scale_get_y(v2d), \ + }, \ + } + +#define UV_NEAREST_HIT_INIT_MAX(v2d) \ { \ .dist_sq = FLT_MAX, \ + .scale = { \ + UI_view2d_scale_get_x(v2d), \ + UI_view2d_scale_get_y(v2d), \ + }, \ } bool uv_find_nearest_vert(struct Scene *scene, @@ -96,7 +117,6 @@ BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene, void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); -void uvedit_pixel_to_float(struct SpaceImage *sima, float pixeldist, float r_dist[2]); /* operators */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index aac5b96f737..167acf7da18 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -187,28 +187,6 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i /** \} */ /* -------------------------------------------------------------------- */ -/** \name Space Conversion - * \{ */ - -void uvedit_pixel_to_float(SpaceImage *sima, float pixeldist, float r_dist[2]) -{ - int width, height; - - if (sima) { - ED_space_image_get_size(sima, &width, &height); - } - else { - width = IMG_SIZE_FALLBACK; - height = IMG_SIZE_FALLBACK; - } - - r_dist[0] = pixeldist / width; - r_dist[1] = pixeldist / height; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Live Unwrap Utilities * \{ */ diff --git a/source/blender/editors/uvedit/uvedit_path.c b/source/blender/editors/uvedit/uvedit_path.c index 51de199c696..016a054cf21 100644 --- a/source/blender/editors/uvedit/uvedit_path.c +++ b/source/blender/editors/uvedit/uvedit_path.c @@ -574,7 +574,7 @@ static bool uv_shortest_path_pick_ex(const SpaceImage *sima, static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - const SpaceImage *sima = CTX_wm_space_image(C); + SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; const char uv_selectmode = ED_uvedit_select_mode_get(scene); @@ -613,7 +613,7 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve BMElem *ele_src = NULL, *ele_dst = NULL; if (uv_selectmode == UV_SELECT_FACE) { - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); if (!uv_find_nearest_face(scene, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -626,7 +626,7 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve } else if (uv_selectmode & UV_SELECT_EDGE) { - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); if (!uv_find_nearest_edge(scene, obedit, co, &hit)) { return OPERATOR_CANCELLED; } @@ -652,7 +652,7 @@ static int uv_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEve ele_dst = (BMElem *)hit.l; } else { - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); if (!uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index bfb01cb073e..118a2263cc3 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -201,21 +201,6 @@ void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const b } } -/** - * Apply a penalty to elements that are already selected - * so elements that aren't already selected are prioritized. - * - * \note This is calculated in screen-space otherwise zooming in on a uv-vert and - * shift-selecting can consider an adjacent point close enough to add to - * the selection rather than de-selecting the closest. - */ -static float uv_select_penalty_default(SpaceImage *sima) -{ - float penalty[2]; - uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty); - return len_v2(penalty); -} - static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, @@ -680,6 +665,7 @@ static BMLoop *uvedit_loop_find_other_boundary_loop_with_visible_face(const Scen bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) { + BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f)); BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; BMLoop *l; @@ -700,7 +686,13 @@ bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNea luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + float delta[2]; + closest_to_line_segment_v2(delta, co, luv->uv, luv_next->uv); + + sub_v2_v2(delta, co); + mul_v2_v2(delta, hit->scale); + + const float dist_test_sq = len_squared_v2(delta); if (dist_test_sq < hit->dist_sq) { hit->efa = efa; @@ -734,6 +726,7 @@ bool uv_find_nearest_edge_multi(Scene *scene, bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final) { + BLI_assert((hit_final->scale[0] > 0.0f) && (hit_final->scale[1] > 0.0f)); BMEditMesh *em = BKE_editmesh_from_object(obedit); bool found = false; @@ -757,7 +750,11 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea float cent[2]; BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent); - const float dist_test_sq = len_squared_v2v2(co, cent); + float delta[2]; + sub_v2_v2v2(delta, co, cent); + mul_v2_v2(delta, hit.scale); + + const float dist_test_sq = len_squared_v2(delta); if (dist_test_sq < hit.dist_sq) { hit.efa = efa; @@ -805,9 +802,10 @@ bool uv_find_nearest_vert(Scene *scene, const float penalty_dist, UvNearestHit *hit_final) { + BLI_assert((hit_final->scale[0] > 0.0f) && (hit_final->scale[1] > 0.0f)); bool found = false; - /* this will fill in hit.vert1 and hit.vert2 */ + /* This will fill in `hit.l`. */ float dist_sq_init = hit_final->dist_sq; UvNearestHit hit = *hit_final; if (uv_find_nearest_edge(scene, obedit, co, &hit)) { @@ -832,14 +830,17 @@ bool uv_find_nearest_vert(Scene *scene, BMLoop *l; int i; BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - float dist_test_sq; MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; - dist_test_sq = square_f(dist_test_sq); - } - else { - dist_test_sq = len_squared_v2v2(co, luv->uv); + + float delta[2]; + + sub_v2_v2v2(delta, co, luv->uv); + mul_v2_v2(delta, hit.scale); + + float dist_test_sq = len_squared_v2(delta); + + if ((penalty_dist != 0.0f) && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + dist_test_sq = square_f(sqrtf(dist_test_sq) + penalty_dist); } if (dist_test_sq <= hit.dist_sq) { @@ -1912,15 +1913,18 @@ static int uv_mouse_select_multi(bContext *C, { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); + const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(®ion->v2d, 75.0f); int selectmode, sticky; bool found_item = false; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ int flush = 0; - const float penalty_dist = uv_select_penalty_default(sima); + /* Penalty (in pixels) applied to elements that are already selected + * so elements that aren't already selected are prioritized. */ + const float penalty_dist = 3.0f * U.pixelsize; /* retrieve operation mode */ if (ts->uv_flag & UV_SYNC_SELECTION) { @@ -1945,8 +1949,6 @@ static int uv_mouse_select_multi(bContext *C, if (selectmode == UV_SELECT_VERTEX) { /* find vertex */ found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - if (found_item) { if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; @@ -1957,8 +1959,6 @@ static int uv_mouse_select_multi(bContext *C, else if (selectmode == UV_SELECT_EDGE) { /* find edge */ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - if (found_item) { if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; @@ -1969,8 +1969,6 @@ static int uv_mouse_select_multi(bContext *C, else if (selectmode == UV_SELECT_FACE) { /* find face */ found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - if (found_item) { BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; BM_mesh_active_face_set(bm, hit.efa); @@ -1978,7 +1976,6 @@ static int uv_mouse_select_multi(bContext *C, } else if (selectmode == UV_SELECT_ISLAND) { found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); } if (!found_item) { @@ -2173,10 +2170,11 @@ static int uv_mouse_select_loop_generic_multi(bContext *C, enum eUVLoopGenericType loop_type) { SpaceImage *sima = CTX_wm_space_image(C); + const ARegion *region = CTX_wm_region(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); bool found_item = false; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ int flush = 0; @@ -2367,6 +2365,7 @@ void UV_OT_select_edge_ring(wmOperatorType *ot) static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick) { + const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); @@ -2374,7 +2373,7 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent bool deselect = false; bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - UvNearestHit hit = UV_NEAREST_HIT_INIT; + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); if (pick) { extend = RNA_boolean_get(op->ptr, "extend"); @@ -2390,8 +2389,6 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent if (event) { /* invoke */ - const ARegion *region = CTX_wm_region(C); - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); RNA_float_set_array(op->ptr, "location", co); } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index c1d222c9368..7b27bb570cc 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -2539,8 +2539,8 @@ static StitchState *stitch_select(bContext *C, { /* add uv under mouse to processed uv's */ float co[2]; - UvNearestHit hit = UV_NEAREST_HIT_INIT; ARegion *region = CTX_wm_region(C); + UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(®ion->v2d); UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); |