Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/mesh/editmesh_rip_edge.c
| Context not available. | |||||
| * | * | ||||
| * based on mouse cursor position, split of vertices along the closest edge. | * based on mouse cursor position, split of vertices along the closest edge. | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BKE_layer.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| Context not available. | |||||
| { | { | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| RegionView3D *rv3d = CTX_wm_region_view3d(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; | BMIter viter; | ||||
| BMVert *v; | BMVert *v; | ||||
| const float mval_fl[2] = {UNPACK2(event->mval)}; | const float mval_fl[2] = {UNPACK2(event->mval)}; | ||||
| Context not available. | |||||
| float projectMat[4][4]; | float projectMat[4][4]; | ||||
| if (bm->totvertsel == 0) | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| return OPERATOR_CANCELLED; | uint objects_len = 0; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); | |||||
| ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); | 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; | |||||
| zero_v2(cent_sco); | if (bm->totvertsel == 0) | ||||
| cent_tot = 0; | continue; | ||||
| /* clear tags and calc screen center */ | ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); | ||||
| 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)) { | zero_v2(cent_sco); | ||||
| float v_sco[2]; | cent_tot = 0; | ||||
| ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); | |||||
| /* 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); | add_v2_v2(cent_sco, v_sco); | ||||
| cent_tot += 1; | 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 */ | |||||
| /* not essential, but gives more expected results with edge selection */ | if (bm->totedgesel) { | ||||
| if (bm->totedgesel) { | /* angle against center can give odd result, | ||||
| /* angle against center can give odd result, | * try re-position the center to the closest edge */ | ||||
| * try re-position the center to the closest edge */ | BMIter eiter; | ||||
| BMIter eiter; | BMEdge *e; | ||||
| BMEdge *e; | float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl); | ||||
| float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl); | |||||
| BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { | |||||
| BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { | if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | ||||
| if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | float e_sco[2][2]; | ||||
| float e_sco[2][2]; | float cent_sco_test[2]; | ||||
| float cent_sco_test[2]; | float dist_sq_test; | ||||
| 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->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->v2->co, e_sco[1], projectMat); | |||||
| closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]); | |||||
| 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); | ||||
| dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl); | if (dist_sq_test < dist_sq_best) { | ||||
| if (dist_sq_test < dist_sq_best) { | dist_sq_best = dist_sq_test; | ||||
| dist_sq_best = dist_sq_test; | |||||
| /* we have a new screen center */ | |||||
| /* we have a new screen center */ | copy_v2_v2(cent_sco, cent_sco_test); | ||||
| copy_v2_v2(cent_sco, cent_sco_test); | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| sub_v2_v2v2(mval_dir, mval_fl, cent_sco); | sub_v2_v2v2(mval_dir, mval_fl, cent_sco); | ||||
| normalize_v2(mval_dir); | normalize_v2(mval_dir); | ||||
| /* operate on selected verts */ | /* operate on selected verts */ | ||||
| BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { | ||||
| BMIter eiter; | BMIter eiter; | ||||
| BMEdge *e; | BMEdge *e; | ||||
| float v_sco[2]; | float v_sco[2]; | ||||
| if (BM_elem_flag_test(v, BM_ELEM_SELECT) && | if (BM_elem_flag_test(v, BM_ELEM_SELECT) && | ||||
| BM_elem_flag_test(v, BM_ELEM_TAG) == false) | BM_elem_flag_test(v, BM_ELEM_TAG) == false) | ||||
| { | { | ||||
| /* Rules for */ | /* Rules for */ | ||||
| float angle_best = FLT_MAX; | float angle_best = FLT_MAX; | ||||
| BMEdge *e_best = NULL; | BMEdge *e_best = NULL; | ||||
| #ifdef USE_TRICKY_EXTEND | #ifdef USE_TRICKY_EXTEND | ||||
| /* first check if we can select the edge to split based on selection-only */ | /* first check if we can select the edge to split based on selection-only */ | ||||
| int tot_sel = 0, tot = 0; | int tot_sel = 0, tot = 0; | ||||
| BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { | 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_HIDDEN)) { | ||||
| if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { | ||||
| e_best = e; | e_best = e; | ||||
| tot_sel += 1; | tot_sel += 1; | ||||
| } | |||||
| tot += 1; | |||||
| } | } | ||||
| tot += 1; | |||||
| } | } | ||||
| } | if (tot_sel != 1) { | ||||
| if (tot_sel != 1) { | e_best = NULL; | ||||
| e_best = NULL; | } | ||||
| } | |||||
| /* only one edge selected, operate on that */ | /* only one edge selected, operate on that */ | ||||
| if (e_best) { | if (e_best) { | ||||
| goto found_edge; | goto found_edge; | ||||
| } | } | ||||
| /* none selected, fall through and find one */ | /* none selected, fall through and find one */ | ||||
| else if (tot_sel == 0) { | else if (tot_sel == 0) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| /* selection not 0 or 1, do nothing */ | /* selection not 0 or 1, do nothing */ | ||||
| else { | else { | ||||
| goto found_edge; | goto found_edge; | ||||
| } | } | ||||
| #endif | #endif | ||||
| ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); | ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat); | ||||
| BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { | 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_HIDDEN)) { | ||||
| BMVert *v_other = BM_edge_other_vert(e, v); | BMVert *v_other = BM_edge_other_vert(e, v); | ||||
| float v_other_sco[2]; | float v_other_sco[2]; | ||||
| float angle_test; | float angle_test; | ||||
| ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat); | 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) */ | /* avoid comparing with view-axis aligned edges (less than a pixel) */ | ||||
| if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) { | if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) { | ||||
| float v_dir[2]; | float v_dir[2]; | ||||
| sub_v2_v2v2(v_dir, v_other_sco, v_sco); | sub_v2_v2v2(v_dir, v_other_sco, v_sco); | ||||
| normalize_v2(v_dir); | normalize_v2(v_dir); | ||||
| angle_test = angle_normalized_v2v2(mval_dir, v_dir); | angle_test = angle_normalized_v2v2(mval_dir, v_dir); | ||||
| if (angle_test < angle_best) { | if (angle_test < angle_best) { | ||||
| angle_best = angle_test; | angle_best = angle_test; | ||||
| e_best = e; | e_best = e; | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| #ifdef USE_TRICKY_EXTEND | #ifdef USE_TRICKY_EXTEND | ||||
| found_edge: | found_edge: | ||||
| #endif | #endif | ||||
| if (e_best) { | if (e_best) { | ||||
| const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT); | const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT); | ||||
| BMVert *v_new; | BMVert *v_new; | ||||
| BMEdge *e_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_vert_select_set(bm, v, false); | ||||
| BM_edge_select_set(bm, e_new, false); | BM_edge_select_set(bm, e_new, false); | ||||
| BM_vert_select_set(bm, v_new, true); | BM_vert_select_set(bm, v_new, true); | ||||
| if (e_select) { | if (e_select) { | ||||
| BM_edge_select_set(bm, e_best, true); | BM_edge_select_set(bm, e_best, true); | ||||
| } | } | ||||
| BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */ | BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */ | ||||
| changed = true; | changed = true; | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (changed) { | |||||
| BM_select_history_clear(bm); | |||||
| BM_mesh_select_mode_flush(bm); | if (changed) { | ||||
| BM_select_history_clear(bm); | |||||
| EDBM_update_generic(em, true, true); | BM_mesh_select_mode_flush(bm); | ||||
| return OPERATOR_FINISHED; | EDBM_update_generic(em, true, true); | ||||
| } | } | ||||
| else { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | } | ||||
| MEM_freeN(objects); | |||||
| return OPERATOR_FINISHED; | |||||
| } | } | ||||
| Context not available. | |||||