2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2004 by Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Joseph Eagar
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/mesh/editmesh_rip.c
32 #include "MEM_guardedalloc.h"
34 #include "DNA_object_types.h"
37 #include "BLI_array.h"
39 #include "BKE_context.h"
40 #include "BKE_report.h"
41 #include "BKE_editmesh.h"
43 #include "RNA_define.h"
44 #include "RNA_access.h"
49 #include "ED_screen.h"
50 #include "ED_transform.h"
51 #include "ED_view3d.h"
54 #include "bmesh_tools.h"
56 #include "mesh_intern.h" /* own include */
59 * helper to find edge for edge_rip,
61 * \param inset is used so we get some useful distance
62 * when comparing multiple edges that meet at the same
63 * point and would result in the same distance.
65 #define INSET_DEFAULT 0.00001f
66 static float edbm_rip_edgedist_squared(
67 ARegion *ar, float mat[4][4],
68 const float co1[3], const float co2[3], const float mvalf[2],
71 float vec1[2], vec2[2], dist_sq;
73 ED_view3d_project_float_v2_m4(ar, co1, vec1, mat);
74 ED_view3d_project_float_v2_m4(ar, co2, vec2, mat);
77 const float dist_2d = len_v2v2(vec1, vec2);
78 if (dist_2d > FLT_EPSILON) {
79 const float dist = inset / dist_2d;
80 BLI_assert(finite(dist));
81 interp_v2_v2v2(vec1, vec1, vec2, dist);
82 interp_v2_v2v2(vec2, vec2, vec1, dist);
86 dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2);
87 BLI_assert(finite(dist_sq));
93 static float edbm_rip_linedist(
94 ARegion *ar, float mat[4][4],
95 const float co1[3], const float co2[3], const float mvalf[2])
97 float vec1[2], vec2[2];
99 ED_view3d_project_float_v2_m4(ar, co1, vec1, mat);
100 ED_view3d_project_float_v2_m4(ar, co2, vec2, mat);
102 return dist_to_line_v2(mvalf, vec1, vec2);
106 /* calculaters a point along the loop tangent which can be used to measure against edges */
107 static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
109 BM_loop_calc_face_tangent(l, l_mid_co);
111 /* scale to average of surrounding edge size, only needs to be approx, but should
112 * be roughly equivalent to the check below which uses the middle of the edge. */
113 mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f);
115 add_v3_v3(l_mid_co, l->v->co);
119 static float edbm_rip_edge_side_measure(
120 BMEdge *e, BMLoop *e_l,
122 float projectMat[4][4], const float fmval[2])
124 float cent[3] = {0, 0, 0}, mid[3];
127 float fmval_tweak[2];
128 float e_v1_co[2], e_v2_co[2];
134 BLI_assert(BM_vert_in_edge(e, e_l->v));
136 /* method for calculating distance:
138 * for each edge: calculate face center, then made a vector
139 * from edge midpoint to face center. offset edge midpoint
140 * by a small amount along this vector. */
142 /* rather then the face center, get the middle of
143 * both edge verts connected to this one */
144 v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v;
145 v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v;
146 mid_v3_v3v3(cent, v1_other->co, v2_other->co);
147 mid_v3_v3v3(mid, e->v1->co, e->v2->co);
149 ED_view3d_project_float_v2_m4(ar, cent, cent, projectMat);
150 ED_view3d_project_float_v2_m4(ar, mid, mid, projectMat);
152 ED_view3d_project_float_v2_m4(ar, e->v1->co, e_v1_co, projectMat);
153 ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat);
155 sub_v2_v2v2(vec, cent, mid);
157 mul_v2_fl(vec, 0.01f);
159 /* rather then adding to both verts, subtract from the mouse */
160 sub_v2_v2v2(fmval_tweak, fmval, vec);
162 score = len_v2v2(e_v1_co, e_v2_co);
164 if (dist_squared_to_line_segment_v2(fmval_tweak, e_v1_co, e_v2_co) >
165 dist_squared_to_line_segment_v2(fmval, e_v1_co, e_v2_co))
175 /* - Advanced selection handling 'ripsel' functions ----- */
178 * How rip selection works
180 * Firstly - rip is basically edge split with side-selection & grab.
181 * Things would be much more simple if we didn't have to worry about side selection
183 * The method used for checking the side of selection is as follows...
184 * - First tag all rip-able edges.
185 * - Build a contiguous edge list by looping over tagged edges and following each ones tagged siblings in both
187 * - The loops are not stored in an array, Instead both loops on either side of each edge has its index values set
188 * to count down from the last edge, this way, once we have the 'last' edge its very easy to walk down the
189 * connected edge loops.
190 * The reason for using loops like this is because when the edges are split we don't which face user gets the newly
191 * created edge (its as good as random so we cant assume new edges will be on once side).
192 * After splitting, its very simple to walk along boundary loops since each only has one edge from a single side.
193 * - The end loop pairs are stored in an array however to support multiple edge-selection-islands, so you can rip
194 * multiple selections at once.
195 * - * Execute the split *
196 * - For each #EdgeLoopPair walk down both sides of the split using the loops and measure which is facing the mouse.
197 * - Deselect the edge loop facing away.
200 * This currently works very poorly with intersecting edge islands (verts with more than 2 tagged edges)
201 * This is nice to but for now not essential.
207 #define IS_VISIT_POSSIBLE(e) (BM_edge_is_manifold(e) && BM_elem_flag_test(e, BM_ELEM_TAG))
208 #define IS_VISIT_DONE(e) ((e)->l && (BM_elem_index_get((e)->l) != INVALID_UID))
209 #define INVALID_UID INT_MIN
211 /* mark, assign uid and step */
212 static BMEdge *edbm_ripsel_edge_mark_step(BMVert *v, const int uid)
216 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
217 if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
220 BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */
222 /* so (IS_VISIT_DONE == true) */
223 BM_elem_index_set(l_a, uid); /* set_dirty */
224 BM_elem_index_set(l_b, uid); /* set_dirty */
232 typedef struct EdgeLoopPair {
237 static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
247 int uid = bm->totedge; /* can start anywhere */
249 EdgeLoopPair *eloop_pairs = NULL;
250 BLI_array_declare(eloop_pairs);
253 /* initialize loops with dummy invalid index values */
254 BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
255 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
256 BM_elem_index_set(l, INVALID_UID); /* set_dirty */
259 bm->elem_index_dirty |= BM_LOOP;
261 /* set contiguous loops ordered 'uid' values for walking after split */
272 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
273 if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
279 if (e_first == NULL) {
285 v_step = e_first->v1;
286 e_step = NULL; /* quiet warning, will never remain this value */
289 while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
290 v_step = BM_edge_other_vert((e_step = e), v_step);
291 uid++; /* only different line */
295 /* this edges loops have the highest uid's, store this to walk down later */
298 /* always store the highest 'uid' edge for the stride */
303 v_step = e_first->v1;
305 while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
306 v_step = BM_edge_other_vert((e_step = e), v_step);
307 uid--; /* only different line */
311 /* stride far enough not to _ever_ overlap range */
313 uid = uid_end + bm->totedge;
315 lp = BLI_array_append_ret(eloop_pairs);
316 BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b); /* no need to check, we know this will be true */
319 BLI_assert(tot == uid_end - uid_start);
322 printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start);
328 lp = BLI_array_append_ret(eloop_pairs);
329 lp->l_a = lp->l_b = NULL;
335 /* - De-Select the worst rip-edge side -------------------------------- */
338 static BMEdge *edbm_ripsel_edge_uid_step(BMEdge *e_orig, BMVert **v_prev)
342 BMVert *v = BM_edge_other_vert(e_orig, *v_prev);
343 const int uid_cmp = BM_elem_index_get(e_orig->l) - 1;
345 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
346 if (BM_elem_index_get(e->l) == uid_cmp) {
354 static BMVert *edbm_ripsel_edloop_pair_start_vert(BMEdge *e)
356 /* try step in a direction, if it fails we know do go the other way */
357 BMVert *v_test = e->v1;
358 return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2;
361 static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs,
362 ARegion *ar, float projectMat[4][4], float fmval[2])
366 for (lp = eloop_pairs; lp->l_a; lp++) {
370 float score_a = 0.0f;
371 float score_b = 0.0f;
374 v_prev = edbm_ripsel_edloop_pair_start_vert(e);
375 for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
376 score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval);
379 v_prev = edbm_ripsel_edloop_pair_start_vert(e);
380 for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
381 score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval);
384 e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e;
385 v_prev = edbm_ripsel_edloop_pair_start_vert(e);
386 for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
387 BM_edge_select_set(bm, e, false);
391 /* --- end 'ripsel' selection handling code --- */
394 /* --- face-fill code --- */
396 * return an un-ordered array of loop pairs
397 * use for rebuilding face-fill
399 * \note the method currenly used fails for edges with 3+ face users and gives
400 * nasty holes in the mesh, there isnt a good way of knowing ahead of time
401 * which loops will be split apart (its possible to figure out but quite involved).
402 * So for now this is a known limitation of current rip-fill option.
405 typedef struct UnorderedLoopPair {
410 ULP_FLIP_0 = (1 << 0),
411 ULP_FLIP_1 = (1 << 1)
414 static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm)
419 unsigned int total_tag = 0;
420 /* count tags, could be pre-calculated */
421 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
422 if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
428 UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__);
429 UnorderedLoopPair *ulp = uloop_pairs;
431 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
432 if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
434 if (BM_edge_loop_pair(e, &l1, &l2)) {
435 BMVert *v_cmp = l1->e->v1;
436 ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) |
437 ((l2->v == v_cmp) ? ULP_FLIP_1 : 0));
456 static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs)
458 UnorderedLoopPair *ulp;
459 unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
462 for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) {
463 if ((ulp->l_pair[0] && ulp->l_pair[1]) &&
464 (ulp->l_pair[0]->e != ulp->l_pair[1]->e))
466 /* time has come to make a face! */
467 BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
468 BMFace *f, *f_example = ulp->l_pair[0]->f;
472 if (v_shared == NULL) {
474 f_verts[0] = ulp->l_pair[0]->e->v1;
475 f_verts[1] = ulp->l_pair[1]->e->v1;
476 f_verts[2] = ulp->l_pair[1]->e->v2;
477 f_verts[3] = ulp->l_pair[0]->e->v2;
479 if (ulp->flag & ULP_FLIP_0) {
480 SWAP(BMVert *, f_verts[0], f_verts[3]);
482 if (ulp->flag & ULP_FLIP_1) {
483 SWAP(BMVert *, f_verts[1], f_verts[2]);
488 f_verts[0] = v_shared;
489 f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared);
490 f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared);
493 /* don't use the flip flags */
494 if (v_shared == ulp->l_pair[0]->v) {
495 SWAP(BMVert *, f_verts[0], f_verts[1]);
499 /* face should never exist */
500 BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false);
502 f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
504 l_iter = BM_FACE_FIRST_LOOP(f);
507 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
508 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next;
509 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next;
510 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
513 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
514 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
515 BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
522 /* --- end 'face-fill' code --- */
525 * This is the main vert ripping function (rip when one vertex is selected)
527 static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *event)
529 const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
530 UnorderedLoopPair *fill_uloop_pairs = NULL;
531 Object *obedit = CTX_data_edit_object(C);
532 ARegion *ar = CTX_wm_region(C);
533 RegionView3D *rv3d = CTX_wm_region_view3d(C);
534 BMEditMesh *em = BKE_editmesh_from_object(obedit);
540 const int totvert_orig = bm->totvert;
542 float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
543 float dist_sq = FLT_MAX;
545 bool is_wire, is_manifold_region;
548 int totboundary_edge = 0;
550 ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
552 /* find selected vert - same some time and check history first */
553 if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) {
554 v = (BMVert *)ese.ele;
559 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
560 if (BM_elem_flag_test(v, BM_ELEM_SELECT))
565 /* (v == NULL) should be impossible */
566 if ((v == NULL) || (v->e == NULL)) {
567 return OPERATOR_CANCELLED;
570 is_wire = BM_vert_is_wire(v);
571 is_manifold_region = BM_vert_is_manifold_region(v);
577 /* find closest edge to mouse cursor */
578 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
579 /* consider wire as boundary for this purpose,
580 * otherwise we can't a face away from a wire edge */
581 totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
582 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
583 if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
584 d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
585 if ((e_best == NULL) || (d < dist_sq)) {
594 if (e_best && (is_manifold_region == false)) {
595 /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
596 BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
599 BLI_assert(l_sep->v == v);
600 v_new = bmesh_urmv_loop_region(bm, l_sep);
601 BLI_assert(BM_vert_find_first_loop(v));
603 BM_vert_select_set(bm, v, false);
604 BM_select_history_remove(bm, v);
606 BM_vert_select_set(bm, v_new, true);
608 BM_select_history_store(bm, v_new);
612 BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
615 return OPERATOR_FINISHED;
618 /* if we are ripping a single vertex from 3 faces,
619 * then measure the distance to the face corner as well as the edge */
620 if (BM_vert_face_count_is_equal(v, 3) &&
621 BM_vert_edge_count_is_equal(v, 3))
627 BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
628 BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
630 /* not do a loop similar to the one above, but test against loops */
631 for (i1 = 0; i1 < 3; i1++) {
632 /* consider wire as boundary for this purpose,
633 * otherwise we can't a face away from a wire edge */
636 edbm_calc_loop_co(l, l_mid_co);
637 d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
638 if ((e_best == NULL) || (d < dist_sq)) {
641 /* find the edge that is not in this loop */
643 for (i2 = 0; i2 < 3; i2++) {
644 if (!BM_edge_in_loop(e_all[i2], l)) {
649 BLI_assert(e_best != NULL);
654 /* should we go ahead with edge rip or do we need to do special case, split off vertex?:
655 * split off vertex if...
656 * - we cant find an edge - this means we are ripping a faces vert that is connected to other
657 * geometry only at the vertex.
658 * - the boundary edge total is greater than 2,
659 * in this case edge split _can_ work but we get far nicer results if we use this special case.
660 * - there are only 2 edges but we are a wire vert. */
661 if ((is_wire == false && totboundary_edge > 2) ||
662 (is_wire == true && totboundary_edge > 1))
667 BM_vert_select_set(bm, v, false);
669 bmesh_vert_separate(bm, v, &vout, &vout_len, true);
673 /* set selection back to avoid active-unselected vertex */
674 BM_vert_select_set(bm, v, true);
675 /* should never happen */
676 BKE_report(op->reports, RPT_ERROR, "Error ripping vertex from faces");
677 return OPERATOR_CANCELLED;
683 BM_select_history_remove(bm, ese.ele);
688 /* in the loop below we find the best vertex to drag based on its connected geometry,
689 * either by its face corner, or connected edge (when no faces are attached) */
690 for (i = 0; i < vout_len; i++) {
692 if (BM_vert_is_wire(vout[i]) == false) {
693 /* find the best face corner */
694 BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) {
695 if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
698 edbm_calc_loop_co(l, l_mid_co);
699 d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT);
710 /* a wire vert, find the best edge */
711 BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
712 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
715 mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co);
716 d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT);
729 * vout[2+] == splice with glue (when vout_len > 2)
732 SWAP(BMVert *, vout[0], vout[vi_best]);
736 /* select the vert from the best region */
738 BM_vert_select_set(bm, v, true);
741 BM_select_history_store(bm, v);
744 /* splice all others back together */
746 for (i = 2; i < vout_len; i++) {
747 BM_vert_splice(bm, vout[1], vout[i]);
753 /* match extrude vert-order */
754 BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
760 return OPERATOR_FINISHED;
765 BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached");
766 return OPERATOR_CANCELLED;
769 /* *** Execute the split! *** */
770 /* unlike edge split, for single vertex split we only use the operator in one of the cases
771 * but both allocate fill */
778 /* rip two adjacent edges */
779 if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) {
780 /* Don't run the edge split operator in this case */
782 l = BM_edge_vert_share_loop(e_best->l, v);
786 /* only tag for face-fill (we don't call the operator) */
787 if (BM_edge_is_boundary(e_best)) {
788 BM_elem_flag_enable(e_best, BM_ELEM_TAG);
791 BM_elem_flag_enable(l->e, BM_ELEM_TAG);
792 BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
796 if (BM_edge_is_manifold(e_best)) {
797 BMLoop *l_iter, *l_first;
798 l_iter = l_first = e_best->l;
800 larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
803 /* Only needed when filling...
804 * Also, we never want to tag best edge, that one won't change during split. See T44618. */
805 if (larr[larr_len]->e == e_best) {
806 BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
809 BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
813 } while ((l_iter = l_iter->radial_next) != l_first);
816 /* looks like there are no split edges, we could just return/report-error? - Campbell */
820 /* keep directly before edgesplit */
822 fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
826 v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
833 BM_vert_select_set(bm, v_rip, true);
836 if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs);
837 return OPERATOR_CANCELLED;
842 /* --- select which vert --- */
843 BMVert *v_best = NULL;
844 float l_corner_co[3];
847 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
848 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
849 /* disable by default, re-enable winner at end */
850 BM_vert_select_set(bm, v, false);
851 BM_select_history_remove(bm, v);
853 BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
855 /* check if v_best is null in the _rare_ case there are numeric issues */
856 edbm_calc_loop_co(l, l_corner_co);
857 d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT);
858 if ((v_best == NULL) || (d < dist_sq)) {
867 BM_vert_select_set(bm, v_best, true);
869 BM_select_history_store(bm, v_best);
874 if (do_fill && fill_uloop_pairs) {
875 edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
876 MEM_freeN(fill_uloop_pairs);
880 if (totvert_orig == bm->totvert) {
881 BKE_report(op->reports, RPT_ERROR, "No vertices could be ripped");
882 return OPERATOR_CANCELLED;
885 return OPERATOR_FINISHED;
889 * This is the main edge ripping function
891 static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *event)
893 const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
894 UnorderedLoopPair *fill_uloop_pairs = NULL;
895 Object *obedit = CTX_data_edit_object(C);
896 ARegion *ar = CTX_wm_region(C);
897 RegionView3D *rv3d = CTX_wm_region_view3d(C);
898 BMEditMesh *em = BKE_editmesh_from_object(obedit);
904 const int totedge_orig = bm->totedge;
905 float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
907 EdgeLoopPair *eloop_pairs;
909 ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
911 /* important this runs on the original selection, before tampering with tagging */
912 eloop_pairs = edbm_ripsel_looptag_helper(bm);
914 /* expand edge selection */
915 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
918 int totedge_manifold; /* manifold, visible edges */
923 totedge_manifold = 0;
925 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
927 if (!BM_edge_is_wire(e) &&
928 !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
930 /* important to check selection rather then tag here
931 * else we get feedback loop */
932 if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
939 /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */
940 if ((all_manifold == true) && (BM_edge_is_manifold(e) == false)) {
941 all_manifold = false;
945 /* single edge, extend */
946 if (i == 1 && e_best->l) {
947 /* note: if the case of 3 edges has one change in loop stepping,
948 * if this becomes more involved we may be better off splitting
949 * the 3 edge case into its own else-if branch */
950 if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
951 BMLoop *l_a = e_best->l;
952 BMLoop *l_b = l_a->radial_next;
954 /* find the best face to follow, this way the edge won't point away from
955 * the mouse when there are more than 4 (takes the shortest face fan around) */
956 l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) <
957 edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? l_a : l_b;
959 l = BM_loop_other_edge_loop(l, v);
960 /* important edge is manifold else we can be attempting to split off a fan that don't budge,
961 * not crashing but adds duplicate edge. */
962 if (BM_edge_is_manifold(l->e)) {
965 if (totedge_manifold != 3)
966 l = BM_loop_other_edge_loop(l, v);
969 BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG));
970 BM_elem_flag_enable(l->e, BM_ELEM_TAG);
975 e = BM_vert_other_disk_edge(v, e_best);
978 BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG));
979 BM_elem_flag_enable(e, BM_ELEM_TAG);
985 /* keep directly before edgesplit */
987 fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
990 BM_mesh_edgesplit(em->bm, true, true, true);
992 /* note: the output of the bmesh operator is ignored, since we built
993 * the contiguous loop pairs to split already, its possible that some
994 * edge did not split even though it was tagged which would not work
995 * as expected (but not crash), however there are checks to ensure
996 * tagged edges will split. So far its not been an issue. */
997 edbm_ripsel_deselect_helper(bm, eloop_pairs,
998 ar, projectMat, fmval);
999 MEM_freeN(eloop_pairs);
1001 /* deselect loose verts */
1002 BM_mesh_select_mode_clean_ex(bm, SCE_SELECT_EDGE);
1004 if (do_fill && fill_uloop_pairs) {
1005 edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
1006 MEM_freeN(fill_uloop_pairs);
1009 if (totedge_orig == bm->totedge) {
1010 BKE_report(op->reports, RPT_ERROR, "No edges could be ripped");
1011 return OPERATOR_CANCELLED;
1014 BM_select_history_validate(bm);
1016 return OPERATOR_FINISHED;
1019 /* based on mouse cursor position, it defines how is being ripped */
1020 static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1022 Object *obedit = CTX_data_edit_object(C);
1023 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1027 const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0);
1030 /* running in face mode hardly makes sense, so convert to region loop and rip */
1031 if (bm->totfacesel) {
1032 /* highly nifty but hard to support since the operator can fail and we're left
1033 * with modified selection */
1034 // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
1036 BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces");
1037 return OPERATOR_CANCELLED;
1040 /* we could support this, but not for now */
1041 if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
1042 BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
1043 return OPERATOR_CANCELLED;
1046 /* note on selection:
1047 * When calling edge split we operate on tagged edges rather then selected
1048 * this is important because the edges to operate on are extended by one,
1049 * but the selection is left alone.
1051 * After calling edge split - the duplicated edges have the same selection state as the
1052 * original, so all we do is de-select the far side from the mouse and we have a
1053 * useful selection for grabbing.
1056 /* BM_ELEM_SELECT --> BM_ELEM_TAG */
1057 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
1058 BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
1061 /* split 2 main parts of this operator out into vertex and edge ripping */
1063 ret = edbm_rip_invoke__vert(C, op, event);
1066 ret = edbm_rip_invoke__edge(C, op, event);
1069 if (ret == OPERATOR_CANCELLED) {
1070 return OPERATOR_CANCELLED;
1073 BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
1075 if (bm->totvertsel == 0) {
1076 return OPERATOR_CANCELLED;
1079 EDBM_update_generic(em, true, true);
1081 return OPERATOR_FINISHED;
1085 void MESH_OT_rip(wmOperatorType *ot)
1089 ot->idname = "MESH_OT_rip";
1090 ot->description = "Disconnect vertex or edges from connected geometry";
1093 ot->invoke = edbm_rip_invoke;
1094 ot->poll = EDBM_view3d_poll;
1097 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1099 /* to give to transform */
1100 Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
1101 RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill the ripped region");