code cleanup: redundant includes and add minor comments.
[blender.git] / source / blender / bmesh / operators / bmo_edgenet.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * Contributor(s): Joseph Eagar.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/operators/bmo_edgenet.c
24  *  \ingroup bmesh
25  *
26  * Edge-Net for filling in open edge-loops.
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_math.h"
32 #include "BLI_array.h"
33
34 #include "bmesh.h"
35 #include "bmesh_tools.h"
36
37 #include "intern/bmesh_operators_private.h" /* own include */
38
39 #define EDGE_MARK       1
40 #define EDGE_VIS        2
41
42 #define ELE_NEW         1
43
44 void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op)
45 {
46         BMOperator op_attr;
47         BMOIter siter;
48         BMFace *f;
49         const short mat_nr        = BMO_slot_int_get(op->slots_in,  "mat_nr");
50         const bool use_smooth     = BMO_slot_bool_get(op->slots_in, "use_smooth");
51 //      const int sides           = BMO_slot_int_get(op->slots_in,  "sides");
52
53         if (!bm->totvert || !bm->totedge)
54                 return;
55
56         BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false);
57         BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false);
58
59         BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
60         BM_mesh_edgenet(bm, true, true); // TODO, sides
61
62         BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
63
64         BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) {
65                 f->mat_nr = mat_nr;
66                 if (use_smooth) {
67                         BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
68                 }
69                 /* normals are zero'd */
70                 BM_face_normal_update(f);
71         }
72
73         /* --- Attribute Fill --- */
74         /* may as well since we have the faces already in a buffer */
75         BMO_op_initf(bm, &op_attr, op->flag,
76                      "face_attribute_fill faces=%S use_normals=%b",
77                      op, "faces.out", true);
78
79         BMO_op_exec(bm, &op_attr);
80
81         /* check if some faces couldn't be touched */
82         if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) {
83                 BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out");
84         }
85         BMO_op_finish(bm, &op_attr);
86
87 }
88
89 static BMEdge *edge_next(BMesh *bm, BMEdge *e)
90 {
91         BMIter iter;
92         BMEdge *e2;
93         int i;
94
95         for (i = 0; i < 2; i++) {
96                 BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) {
97                         if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) &&
98                             (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) &&
99                             (e2 != e))
100                         {
101                                 return e2;
102                         }
103                 }
104         }
105
106         return NULL;
107 }
108
109 void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
110 {
111         BMOIter siter;
112         BMEdge *e;
113         BMEdge **edges1 = NULL, **edges2 = NULL, **edges;
114         BLI_array_declare(edges1);
115         BLI_array_declare(edges2);
116         BLI_array_declare(edges);
117         int ok = 1;
118         int i, count;
119
120         BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK);
121
122         /* validate that each edge has at most one other tagged edge in the
123          * disk cycle around each of it's vertices */
124         BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
125                 for (i = 0; i < 2; i++) {
126                         count = BMO_iter_elem_count_flag(bm,  BM_EDGES_OF_VERT, (i ? e->v2 : e->v1), EDGE_MARK, true);
127                         if (count > 2) {
128                                 ok = 0;
129                                 break;
130                         }
131                 }
132
133                 if (!ok) {
134                         break;
135                 }
136         }
137
138         /* we don't have valid edge layouts, retur */
139         if (!ok) {
140                 return;
141         }
142
143         /* find connected loops within the input edge */
144         count = 0;
145         while (1) {
146                 BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
147                         if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) {
148                                 if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 ||
149                                     BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1)
150                                 {
151                                         break;
152                                 }
153                         }
154                 }
155
156                 if (!e) {
157                         break;
158                 }
159
160                 if (!count) {
161                         edges = edges1;
162                 }
163                 else if (count == 1) {
164                         edges = edges2;
165                 }
166                 else {
167                         break;
168                 }
169
170                 i = 0;
171                 while (e) {
172                         BMO_elem_flag_enable(bm, e, EDGE_VIS);
173                         BLI_array_grow_one(edges);
174                         edges[i] = e;
175
176                         e = edge_next(bm, e);
177                         i++;
178                 }
179
180                 if (!count) {
181                         edges1 = edges;
182                         BLI_array_length_set(edges1, BLI_array_count(edges));
183                 }
184                 else {
185                         edges2 = edges;
186                         BLI_array_length_set(edges2, BLI_array_count(edges));
187                 }
188
189                 BLI_array_empty(edges);
190                 count++;
191         }
192
193         if (edges1 && BLI_array_count(edges1) > 2 &&
194             BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1]))
195         {
196                 if (edges2 && BLI_array_count(edges2) > 2 &&
197                     BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1]))
198                 {
199                         BLI_array_free(edges1);
200                         BLI_array_free(edges2);
201                         return;
202                 }
203                 else {
204                         edges1 = edges2;
205                         edges2 = NULL;
206                 }
207         }
208
209         if (edges2 && BLI_array_count(edges2) > 2 &&
210             BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1]))
211         {
212                 edges2 = NULL;
213         }
214
215         /* two unconnected loops, connect the */
216         if (edges1 && edges2) {
217                 BMVert *v1, *v2, *v3, *v4;
218                 float dvec1[3];
219                 float dvec2[3];
220
221                 if (BLI_array_count(edges1) == 1) {
222                         v1 = edges1[0]->v1;
223                         v2 = edges1[0]->v2;
224                 }
225                 else {
226                         v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1;
227                         i  = BLI_array_count(edges1) - 1;
228                         v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
229                 }
230
231                 if (BLI_array_count(edges2) == 1) {
232                         v3 = edges2[0]->v1;
233                         v4 = edges2[0]->v2;
234                 }
235                 else {
236                         v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1;
237                         i  = BLI_array_count(edges2) - 1;
238                         v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1;
239                 }
240
241                 /* if there is ever bow-tie quads between two edges the problem is here! [#30367] */
242 #if 0
243                 normal_tri_v3(dvec1, v1->co, v2->co, v4->co);
244                 normal_tri_v3(dvec2, v1->co, v4->co, v3->co);
245 #else
246                 {
247                         /* save some CPU cycles and skip the sqrt and 1 subtraction */
248                         float a1[3], a2[3], a3[3];
249                         sub_v3_v3v3(a1, v1->co, v2->co);
250                         sub_v3_v3v3(a2, v1->co, v4->co);
251                         sub_v3_v3v3(a3, v1->co, v3->co);
252                         cross_v3_v3v3(dvec1, a1, a2);
253                         cross_v3_v3v3(dvec2, a2, a3);
254                 }
255 #endif
256                 if (dot_v3v3(dvec1, dvec2) < 0.0f) {
257                         SWAP(BMVert *, v3, v4);
258                 }
259
260                 e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE);
261                 BMO_elem_flag_enable(bm, e, ELE_NEW);
262                 e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE);
263                 BMO_elem_flag_enable(bm, e, ELE_NEW);
264         }
265         else if (edges1) {
266                 BMVert *v1, *v2;
267
268                 if (BLI_array_count(edges1) > 1) {
269                         v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1;
270                         i  = BLI_array_count(edges1) - 1;
271                         v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1;
272                         e  = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE);
273                         BMO_elem_flag_enable(bm, e, ELE_NEW);
274                 }
275         }
276
277         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW);
278
279         BLI_array_free(edges1);
280         BLI_array_free(edges2);
281 }