1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup bmesh
19  *
20  * Edge-Split.
21  */
22 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_utildefines.h"
26 
27 #include "bmesh.h"
28 
29 #include "bmesh_edgesplit.h" /* own include */
30 
31 /**
32  * \param use_verts: Use flagged verts instead of edges.
33  * \param tag_only: Only split tagged edges.
34  * \param copy_select: Copy selection history.
35  */
BM_mesh_edgesplit(BMesh * bm,const bool use_verts,const bool tag_only,const bool copy_select)36 void BM_mesh_edgesplit(BMesh *bm,
37                        const bool use_verts,
38                        const bool tag_only,
39                        const bool copy_select)
40 {
41   BMIter iter;
42   BMEdge *e;
43 
44   bool use_ese = false;
45   GHash *ese_gh = NULL;
46 
47   if (copy_select && bm->selected.first) {
48     BMEditSelection *ese;
49 
50     ese_gh = BLI_ghash_ptr_new(__func__);
51     for (ese = bm->selected.first; ese; ese = ese->next) {
52       if (ese->htype != BM_FACE) {
53         BLI_ghash_insert(ese_gh, ese->ele, ese);
54       }
55     }
56 
57     use_ese = true;
58   }
59 
60   if (tag_only == false) {
61     BM_mesh_elem_hflag_enable_all(bm, BM_EDGE | (use_verts ? BM_VERT : 0), BM_ELEM_TAG, false);
62   }
63 
64   if (use_verts) {
65     /* prevent one edge having both verts unflagged
66      * we could alternately disable these edges, either way its a corner case.
67      *
68      * This is needed so we don't split off the edge but then none of its verts which
69      * would leave a duplicate edge.
70      */
71     BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
72       if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
73         if (UNLIKELY(((BM_elem_flag_test(e->v1, BM_ELEM_TAG) == false) &&
74                       (BM_elem_flag_test(e->v2, BM_ELEM_TAG) == false)))) {
75           BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
76           BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
77         }
78       }
79     }
80   }
81   else {
82     BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
83       if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
84         BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
85         BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
86       }
87     }
88   }
89 
90   BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
91     if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
92       uint i;
93       for (i = 0; i < 2; i++) {
94         BMVert *v = ((&e->v1)[i]);
95         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
96           BM_elem_flag_disable(v, BM_ELEM_TAG);
97 
98           if (use_ese) {
99             BMVert **vtar;
100             int vtar_len;
101 
102             BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, &vtar, &vtar_len);
103 
104             /* first value is always in 'v' */
105             if (vtar_len > 1) {
106               BMEditSelection *ese = BLI_ghash_lookup(ese_gh, v);
107               BLI_assert(v == vtar[0]);
108               if (UNLIKELY(ese)) {
109                 int j;
110                 for (j = 1; j < vtar_len; j++) {
111                   BLI_assert(v != vtar[j]);
112                   BM_select_history_store_after_notest(bm, ese, vtar[j]);
113                 }
114               }
115             }
116             MEM_freeN(vtar);
117           }
118           else {
119             BM_vert_separate_hflag(bm, v, BM_ELEM_TAG, copy_select, NULL, NULL);
120           }
121         }
122       }
123     }
124   }
125 
126 #ifndef NDEBUG
127   /* ensure we don't have any double edges! */
128   BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
129     if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
130       BLI_assert(BM_edge_find_double(e) == NULL);
131     }
132   }
133 #endif
134 
135   if (use_ese) {
136     BLI_ghash_free(ese_gh, NULL, NULL);
137   }
138 }
139