UV: add path select operator that uses the selection
Instead of using the mouse cursor position, this selects between existing selected elements. Access this since picking a selection path doesn't work from the menu.
This commit is contained in:
parent
6e698653df
commit
415d3ee05b
|
@ -191,7 +191,7 @@ class IMAGE_MT_select_linked(Menu):
|
|||
layout = self.layout
|
||||
|
||||
layout.operator("uv.select_linked", text="Linked")
|
||||
layout.operator("uv.shortest_path_pick", text="Shortest Path")
|
||||
layout.operator("uv.shortest_path_select", text="Shortest Path")
|
||||
|
||||
|
||||
class IMAGE_MT_image(Menu):
|
||||
|
|
|
@ -175,6 +175,19 @@ bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
|
|||
float *dist_sq,
|
||||
float r_uv[2]);
|
||||
|
||||
struct BMFace **ED_uvedit_selected_faces(struct Scene *scene,
|
||||
struct BMesh *bm,
|
||||
int len_max,
|
||||
int *r_faces_len);
|
||||
struct BMLoop **ED_uvedit_selected_edges(struct Scene *scene,
|
||||
struct BMesh *bm,
|
||||
int len_max,
|
||||
int *r_edges_len);
|
||||
struct BMLoop **ED_uvedit_selected_verts(struct Scene *scene,
|
||||
struct BMesh *bm,
|
||||
int len_max,
|
||||
int *r_verts_len);
|
||||
|
||||
void ED_uvedit_get_aspect(struct Object *obedit, float *r_aspx, float *r_aspy);
|
||||
|
||||
void ED_uvedit_active_vert_loop_set(struct BMesh *bm, struct BMLoop *l);
|
||||
|
|
|
@ -111,6 +111,7 @@ void UV_OT_stitch(struct wmOperatorType *ot);
|
|||
|
||||
/* uvedit_path.c */
|
||||
void UV_OT_shortest_path_pick(struct wmOperatorType *ot);
|
||||
void UV_OT_shortest_path_select(struct wmOperatorType *ot);
|
||||
|
||||
/* uvedit_select.c */
|
||||
|
||||
|
|
|
@ -2090,6 +2090,7 @@ void ED_operatortypes_uvedit(void)
|
|||
WM_operatortype_append(UV_OT_rip);
|
||||
WM_operatortype_append(UV_OT_stitch);
|
||||
WM_operatortype_append(UV_OT_shortest_path_pick);
|
||||
WM_operatortype_append(UV_OT_shortest_path_select);
|
||||
|
||||
WM_operatortype_append(UV_OT_seams_from_islands);
|
||||
WM_operatortype_append(UV_OT_mark_seam);
|
||||
|
|
|
@ -677,3 +677,95 @@ void UV_OT_shortest_path_pick(wmOperatorType *ot)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Select Path Between Existing Selection
|
||||
* \{ */
|
||||
|
||||
static int uv_shortest_path_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const ToolSettings *ts = scene->toolsettings;
|
||||
bool found_valid_elements = false;
|
||||
|
||||
float aspect_y;
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
float aspx, aspy;
|
||||
ED_uvedit_get_aspect(obedit, &aspx, &aspy);
|
||||
aspect_y = aspx / aspy;
|
||||
}
|
||||
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
uint objects_len = 0;
|
||||
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
||||
view_layer, CTX_wm_view3d(C), &objects_len);
|
||||
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
||||
Object *obedit = objects[ob_index];
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMesh *bm = em->bm;
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
BMElem *ele_src = NULL, *ele_dst = NULL;
|
||||
|
||||
/* Find 2x elements. */
|
||||
{
|
||||
BMElem **ele_array = NULL;
|
||||
int ele_array_len = 0;
|
||||
if (ts->uv_selectmode & UV_SELECT_FACE) {
|
||||
ele_array = (BMElem **)ED_uvedit_selected_faces(scene, bm, 3, &ele_array_len);
|
||||
}
|
||||
else if (ts->uv_selectmode & UV_SELECT_EDGE) {
|
||||
ele_array = (BMElem **)ED_uvedit_selected_edges(scene, bm, 3, &ele_array_len);
|
||||
}
|
||||
else {
|
||||
ele_array = (BMElem **)ED_uvedit_selected_verts(scene, bm, 3, &ele_array_len);
|
||||
}
|
||||
|
||||
if (ele_array_len == 2) {
|
||||
ele_src = ele_array[0];
|
||||
ele_dst = ele_array[1];
|
||||
}
|
||||
MEM_freeN(ele_array);
|
||||
}
|
||||
|
||||
if (ele_src && ele_dst) {
|
||||
struct PathSelectParams op_params;
|
||||
path_select_params_from_op(op, &op_params);
|
||||
|
||||
uv_shortest_path_pick_ex(
|
||||
scene, depsgraph, obedit, &op_params, ele_src, ele_dst, aspect_y, cd_loop_uv_offset);
|
||||
|
||||
found_valid_elements = true;
|
||||
}
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
if (!found_valid_elements) {
|
||||
BKE_report(
|
||||
op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void UV_OT_shortest_path_select(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Select Shortest Path";
|
||||
ot->idname = "UV_OT_shortest_path_select";
|
||||
ot->description = "Selected shortest path between two vertices/edges/faces";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = uv_shortest_path_select_exec;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
path_select_properties(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -3419,3 +3419,154 @@ void UV_OT_select_overlap(wmOperatorType *ot)
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
|
||||
*
|
||||
* These functions return single elements per connected vertex/edge.
|
||||
* So an edge that has two connected edge loops only assigns one loop in the array.
|
||||
* \{ */
|
||||
|
||||
BMFace **ED_uvedit_selected_faces(Scene *scene, BMesh *bm, int len_max, int *r_faces_len)
|
||||
{
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
CLAMP_MAX(len_max, bm->totface);
|
||||
int faces_len = 0;
|
||||
BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__);
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (uvedit_face_visible_test(scene, f)) {
|
||||
if (uvedit_face_select_test(scene, f, cd_loop_uv_offset)) {
|
||||
faces[faces_len++] = f;
|
||||
if (faces_len == len_max) {
|
||||
goto finally;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
*r_faces_len = faces_len;
|
||||
if (faces_len != len_max) {
|
||||
faces = MEM_reallocN(faces, sizeof(*faces) * faces_len);
|
||||
}
|
||||
return faces;
|
||||
}
|
||||
|
||||
BMLoop **ED_uvedit_selected_edges(Scene *scene, BMesh *bm, int len_max, int *r_edges_len)
|
||||
{
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
CLAMP_MAX(len_max, bm->totloop);
|
||||
int edges_len = 0;
|
||||
BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__);
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
|
||||
/* Clear tag. */
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMIter liter;
|
||||
BMLoop *l_iter;
|
||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (uvedit_face_visible_test(scene, f)) {
|
||||
BMIter liter;
|
||||
BMLoop *l_iter;
|
||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
|
||||
const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
|
||||
const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset);
|
||||
if ((luv_curr->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) {
|
||||
BM_elem_flag_enable(l_iter, BM_ELEM_TAG);
|
||||
|
||||
edges[edges_len++] = l_iter;
|
||||
if (edges_len == len_max) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
/* Tag other connected loops so we don't consider them separate edges. */
|
||||
if (l_iter != l_iter->radial_next) {
|
||||
BMLoop *l_radial_iter = l_iter->radial_next;
|
||||
do {
|
||||
if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, cd_loop_uv_offset)) {
|
||||
BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG);
|
||||
}
|
||||
} while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
*r_edges_len = edges_len;
|
||||
if (edges_len != len_max) {
|
||||
edges = MEM_reallocN(edges, sizeof(*edges) * edges_len);
|
||||
}
|
||||
return edges;
|
||||
}
|
||||
|
||||
BMLoop **ED_uvedit_selected_verts(Scene *scene, BMesh *bm, int len_max, int *r_verts_len)
|
||||
{
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
CLAMP_MAX(len_max, bm->totloop);
|
||||
int verts_len = 0;
|
||||
BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__);
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
|
||||
/* Clear tag. */
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BMIter liter;
|
||||
BMLoop *l_iter;
|
||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
BM_elem_flag_disable(l_iter, BM_ELEM_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (uvedit_face_visible_test(scene, f)) {
|
||||
BMIter liter;
|
||||
BMLoop *l_iter;
|
||||
BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
|
||||
const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
|
||||
if ((luv->flag & MLOOPUV_VERTSEL)) {
|
||||
BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
|
||||
|
||||
verts[verts_len++] = l_iter;
|
||||
if (verts_len == len_max) {
|
||||
goto finally;
|
||||
}
|
||||
|
||||
/* Tag other connected loops so we don't consider them separate vertices. */
|
||||
BMIter liter_disk;
|
||||
BMLoop *l_disk_iter;
|
||||
BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) {
|
||||
if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, cd_loop_uv_offset)) {
|
||||
BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finally:
|
||||
*r_verts_len = verts_len;
|
||||
if (verts_len != len_max) {
|
||||
verts = MEM_reallocN(verts, sizeof(*verts) * verts_len);
|
||||
}
|
||||
return verts;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
Loading…
Reference in New Issue