Multi-Object-Editing : Support for MESH_OT_rip_edge by Miguel Pozo
Maniphest Tasks: T54643 Differential Revision: https://developer.blender.org/D3268
This commit is contained in:
parent
d152a326f9
commit
6539c1fc41
Notes:
blender-bot
2023-02-14 08:38:11 +01:00
Referenced by issue #54643, Multi-Object-Mode: EditMesh Tools
|
@ -24,6 +24,8 @@
|
|||
* based on mouse cursor position, split of vertices along the closest edge.
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
@ -31,6 +33,7 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_layer.h"
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
|
@ -50,181 +53,187 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
|
|||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
BMesh *bm = em->bm;
|
||||
BMIter viter;
|
||||
BMVert *v;
|
||||
const float mval_fl[2] = {UNPACK2(event->mval)};
|
||||
float cent_sco[2];
|
||||
int cent_tot;
|
||||
bool changed = false;
|
||||
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, &objects_len);
|
||||
|
||||
/* mouse direction to view center */
|
||||
float mval_dir[2];
|
||||
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;
|
||||
|
||||
float projectMat[4][4];
|
||||
BMIter viter;
|
||||
BMVert *v;
|
||||
const float mval_fl[2] = { UNPACK2(event->mval) };
|
||||
float cent_sco[2];
|
||||
int cent_tot;
|
||||
bool changed = false;
|
||||
|
||||
if (bm->totvertsel == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
/* mouse direction to view center */
|
||||
float mval_dir[2];
|
||||
|
||||
ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
|
||||
float projectMat[4][4];
|
||||
|
||||
zero_v2(cent_sco);
|
||||
cent_tot = 0;
|
||||
if (bm->totvertsel == 0)
|
||||
continue;
|
||||
|
||||
/* clear tags and calc screen center */
|
||||
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||
BM_elem_flag_disable(v, BM_ELEM_TAG);
|
||||
ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
|
||||
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||
float v_sco[2];
|
||||
ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
|
||||
zero_v2(cent_sco);
|
||||
cent_tot = 0;
|
||||
|
||||
add_v2_v2(cent_sco, v_sco);
|
||||
cent_tot += 1;
|
||||
/* clear tags and calc screen center */
|
||||
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||
BM_elem_flag_disable(v, BM_ELEM_TAG);
|
||||
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
||||
float v_sco[2];
|
||||
ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
|
||||
|
||||
add_v2_v2(cent_sco, v_sco);
|
||||
cent_tot += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
|
||||
mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
|
||||
|
||||
/* not essential, but gives more expected results with edge selection */
|
||||
if (bm->totedgesel) {
|
||||
/* angle against center can give odd result,
|
||||
* try re-position the center to the closest edge */
|
||||
BMIter eiter;
|
||||
BMEdge *e;
|
||||
float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
|
||||
/* not essential, but gives more expected results with edge selection */
|
||||
if (bm->totedgesel) {
|
||||
/* angle against center can give odd result,
|
||||
* try re-position the center to the closest edge */
|
||||
BMIter eiter;
|
||||
BMEdge *e;
|
||||
float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
|
||||
|
||||
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
float e_sco[2][2];
|
||||
float cent_sco_test[2];
|
||||
float dist_sq_test;
|
||||
BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) {
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
float e_sco[2][2];
|
||||
float cent_sco_test[2];
|
||||
float dist_sq_test;
|
||||
|
||||
ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat);
|
||||
ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat);
|
||||
ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat);
|
||||
ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat);
|
||||
|
||||
closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
|
||||
dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
|
||||
if (dist_sq_test < dist_sq_best) {
|
||||
dist_sq_best = dist_sq_test;
|
||||
closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
|
||||
dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
|
||||
if (dist_sq_test < dist_sq_best) {
|
||||
dist_sq_best = dist_sq_test;
|
||||
|
||||
/* we have a new screen center */
|
||||
copy_v2_v2(cent_sco, cent_sco_test);
|
||||
/* we have a new screen center */
|
||||
copy_v2_v2(cent_sco, cent_sco_test);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
|
||||
normalize_v2(mval_dir);
|
||||
sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
|
||||
normalize_v2(mval_dir);
|
||||
|
||||
/* operate on selected verts */
|
||||
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||
BMIter eiter;
|
||||
BMEdge *e;
|
||||
float v_sco[2];
|
||||
/* operate on selected verts */
|
||||
BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
|
||||
BMIter eiter;
|
||||
BMEdge *e;
|
||||
float v_sco[2];
|
||||
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT) &&
|
||||
BM_elem_flag_test(v, BM_ELEM_TAG) == false)
|
||||
{
|
||||
/* Rules for */
|
||||
float angle_best = FLT_MAX;
|
||||
BMEdge *e_best = NULL;
|
||||
if (BM_elem_flag_test(v, BM_ELEM_SELECT) &&
|
||||
BM_elem_flag_test(v, BM_ELEM_TAG) == false)
|
||||
{
|
||||
/* Rules for */
|
||||
float angle_best = FLT_MAX;
|
||||
BMEdge *e_best = NULL;
|
||||
|
||||
#ifdef USE_TRICKY_EXTEND
|
||||
/* first check if we can select the edge to split based on selection-only */
|
||||
int tot_sel = 0, tot = 0;
|
||||
/* first check if we can select the edge to split based on selection-only */
|
||||
int tot_sel = 0, tot = 0;
|
||||
|
||||
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
e_best = e;
|
||||
tot_sel += 1;
|
||||
}
|
||||
tot += 1;
|
||||
}
|
||||
}
|
||||
if (tot_sel != 1) {
|
||||
e_best = NULL;
|
||||
}
|
||||
|
||||
/* only one edge selected, operate on that */
|
||||
if (e_best) {
|
||||
goto found_edge;
|
||||
}
|
||||
/* none selected, fall through and find one */
|
||||
else if (tot_sel == 0) {
|
||||
/* pass */
|
||||
}
|
||||
/* selection not 0 or 1, do nothing */
|
||||
else {
|
||||
goto found_edge;
|
||||
}
|
||||
#endif
|
||||
ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
|
||||
|
||||
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
||||
BMVert *v_other = BM_edge_other_vert(e, v);
|
||||
float v_other_sco[2];
|
||||
float angle_test;
|
||||
|
||||
ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat);
|
||||
|
||||
/* avoid comparing with view-axis aligned edges (less than a pixel) */
|
||||
if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
|
||||
float v_dir[2];
|
||||
|
||||
sub_v2_v2v2(v_dir, v_other_sco, v_sco);
|
||||
normalize_v2(v_dir);
|
||||
|
||||
angle_test = angle_normalized_v2v2(mval_dir, v_dir);
|
||||
|
||||
if (angle_test < angle_best) {
|
||||
angle_best = angle_test;
|
||||
BM_ITER_ELEM(e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
|
||||
e_best = e;
|
||||
tot_sel += 1;
|
||||
}
|
||||
tot += 1;
|
||||
}
|
||||
}
|
||||
if (tot_sel != 1) {
|
||||
e_best = NULL;
|
||||
}
|
||||
|
||||
/* only one edge selected, operate on that */
|
||||
if (e_best) {
|
||||
goto found_edge;
|
||||
}
|
||||
/* none selected, fall through and find one */
|
||||
else if (tot_sel == 0) {
|
||||
/* pass */
|
||||
}
|
||||
/* selection not 0 or 1, do nothing */
|
||||
else {
|
||||
goto found_edge;
|
||||
}
|
||||
#endif
|
||||
ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
|
||||
|
||||
BM_ITER_ELEM(e, &eiter, v, BM_EDGES_OF_VERT) {
|
||||
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
|
||||
BMVert *v_other = BM_edge_other_vert(e, v);
|
||||
float v_other_sco[2];
|
||||
float angle_test;
|
||||
|
||||
ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat);
|
||||
|
||||
/* avoid comparing with view-axis aligned edges (less than a pixel) */
|
||||
if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
|
||||
float v_dir[2];
|
||||
|
||||
sub_v2_v2v2(v_dir, v_other_sco, v_sco);
|
||||
normalize_v2(v_dir);
|
||||
|
||||
angle_test = angle_normalized_v2v2(mval_dir, v_dir);
|
||||
|
||||
if (angle_test < angle_best) {
|
||||
angle_best = angle_test;
|
||||
e_best = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_TRICKY_EXTEND
|
||||
found_edge:
|
||||
found_edge :
|
||||
#endif
|
||||
if (e_best) {
|
||||
const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
|
||||
BMVert *v_new;
|
||||
BMEdge *e_new;
|
||||
if (e_best) {
|
||||
const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
|
||||
BMVert *v_new;
|
||||
BMEdge *e_new;
|
||||
|
||||
v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
|
||||
v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
|
||||
|
||||
BM_vert_select_set(bm, v, false);
|
||||
BM_edge_select_set(bm, e_new, false);
|
||||
BM_vert_select_set(bm, v, false);
|
||||
BM_edge_select_set(bm, e_new, false);
|
||||
|
||||
BM_vert_select_set(bm, v_new, true);
|
||||
if (e_select) {
|
||||
BM_edge_select_set(bm, e_best, true);
|
||||
BM_vert_select_set(bm, v_new, true);
|
||||
if (e_select) {
|
||||
BM_edge_select_set(bm, e_best, true);
|
||||
}
|
||||
BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
|
||||
|
||||
changed = true;
|
||||
}
|
||||
BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
BM_select_history_clear(bm);
|
||||
|
||||
BM_mesh_select_mode_flush(bm);
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
BM_select_history_clear(bm);
|
||||
MEM_freeN(objects);
|
||||
|
||||
BM_mesh_select_mode_flush(bm);
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue