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  * Convert triangle to quads.
21  *
22  * TODO
23  * - convert triangles to any sided faces, not just quads.
24  */
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "DNA_meshdata_types.h"
29 
30 #include "BLI_math.h"
31 #include "BLI_sort_utils.h"
32 
33 #include "BKE_customdata.h"
34 
35 #include "bmesh.h"
36 
37 #include "intern/bmesh_operators_private.h" /* own include */
38 
39 /* assumes edges are validated before reaching this poin */
quad_calc_error(const float v1[3],const float v2[3],const float v3[3],const float v4[3])40 static float quad_calc_error(const float v1[3],
41                              const float v2[3],
42                              const float v3[3],
43                              const float v4[3])
44 {
45   /* Gives a 'weight' to a pair of triangles that join an edge
46    * to decide how good a join they would make. */
47   /* Note: this is more complicated than it needs to be and should be cleaned up.. */
48   float error = 0.0f;
49 
50   /* Normal difference */
51   {
52     float n1[3], n2[3];
53     float angle_a, angle_b;
54     float diff;
55 
56     normal_tri_v3(n1, v1, v2, v3);
57     normal_tri_v3(n2, v1, v3, v4);
58     angle_a = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
59 
60     normal_tri_v3(n1, v2, v3, v4);
61     normal_tri_v3(n2, v4, v1, v2);
62     angle_b = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2);
63 
64     diff = (angle_a + angle_b) / (float)(M_PI * 2);
65 
66     error += diff;
67   }
68 
69   /* Colinearity */
70   {
71     float edge_vecs[4][3];
72     float diff;
73 
74     sub_v3_v3v3(edge_vecs[0], v1, v2);
75     sub_v3_v3v3(edge_vecs[1], v2, v3);
76     sub_v3_v3v3(edge_vecs[2], v3, v4);
77     sub_v3_v3v3(edge_vecs[3], v4, v1);
78 
79     normalize_v3(edge_vecs[0]);
80     normalize_v3(edge_vecs[1]);
81     normalize_v3(edge_vecs[2]);
82     normalize_v3(edge_vecs[3]);
83 
84     /* a completely skinny face is 'pi' after halving */
85     diff = (fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) +
86             fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) +
87             fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) +
88             fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2)) /
89            (float)(M_PI * 2);
90 
91     error += diff;
92   }
93 
94   /* Concavity */
95   {
96     float area_min, area_max, area_a, area_b;
97     float diff;
98 
99     area_a = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4);
100     area_b = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2);
101 
102     area_min = min_ff(area_a, area_b);
103     area_max = max_ff(area_a, area_b);
104 
105     diff = area_max ? (1.0f - (area_min / area_max)) : 1.0f;
106 
107     error += diff;
108   }
109 
110   return error;
111 }
112 
bm_edge_to_quad_verts(const BMEdge * e,const BMVert * r_v_quad[4])113 static void bm_edge_to_quad_verts(const BMEdge *e, const BMVert *r_v_quad[4])
114 {
115   BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3);
116   BLI_assert(BM_edge_is_manifold(e));
117   r_v_quad[0] = e->l->v;
118   r_v_quad[1] = e->l->prev->v;
119   r_v_quad[2] = e->l->next->v;
120   r_v_quad[3] = e->l->radial_next->prev->v;
121 }
122 
123 /* cache customdata delimiters */
124 struct DelimitData_CD {
125   int cd_type;
126   int cd_size;
127   int cd_offset;
128   int cd_offset_end;
129 };
130 
131 struct DelimitData {
132   uint do_seam : 1;
133   uint do_sharp : 1;
134   uint do_mat : 1;
135   uint do_angle_face : 1;
136   uint do_angle_shape : 1;
137 
138   float angle_face;
139   float angle_face__cos;
140 
141   float angle_shape;
142 
143   struct DelimitData_CD cdata[4];
144   int cdata_len;
145 };
146 
bm_edge_is_contiguous_loop_cd_all(const BMEdge * e,const struct DelimitData_CD * delimit_data)147 static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e,
148                                               const struct DelimitData_CD *delimit_data)
149 {
150   int cd_offset;
151   for (cd_offset = delimit_data->cd_offset; cd_offset < delimit_data->cd_offset_end;
152        cd_offset += delimit_data->cd_size) {
153     if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_type, cd_offset) == false) {
154       return false;
155     }
156   }
157 
158   return true;
159 }
160 
bm_edge_delimit_cdata(CustomData * ldata,CustomDataType type,struct DelimitData_CD * r_delim_cd)161 static bool bm_edge_delimit_cdata(CustomData *ldata,
162                                   CustomDataType type,
163                                   struct DelimitData_CD *r_delim_cd)
164 {
165   const int layer_len = CustomData_number_of_layers(ldata, type);
166   r_delim_cd->cd_type = type;
167   r_delim_cd->cd_size = CustomData_sizeof(r_delim_cd->cd_type);
168   r_delim_cd->cd_offset = CustomData_get_n_offset(ldata, type, 0);
169   r_delim_cd->cd_offset_end = r_delim_cd->cd_offset + (r_delim_cd->cd_size * layer_len);
170   return (r_delim_cd->cd_offset != -1);
171 }
172 
bm_edge_is_delimit(const BMEdge * e,const struct DelimitData * delimit_data)173 static float bm_edge_is_delimit(const BMEdge *e, const struct DelimitData *delimit_data)
174 {
175   BMFace *f_a = e->l->f, *f_b = e->l->radial_next->f;
176 #if 0
177   const bool is_contig = BM_edge_is_contiguous(e);
178   float angle;
179 #endif
180 
181   if ((delimit_data->do_seam) && (BM_elem_flag_test(e, BM_ELEM_SEAM))) {
182     goto fail;
183   }
184 
185   if ((delimit_data->do_sharp) && (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0)) {
186     goto fail;
187   }
188 
189   if ((delimit_data->do_mat) && (f_a->mat_nr != f_b->mat_nr)) {
190     goto fail;
191   }
192 
193   if (delimit_data->do_angle_face) {
194     if (dot_v3v3(f_a->no, f_b->no) < delimit_data->angle_face__cos) {
195       goto fail;
196     }
197   }
198 
199   if (delimit_data->do_angle_shape) {
200     const BMVert *verts[4];
201     bm_edge_to_quad_verts(e, verts);
202 
203     /* if we're checking the shape at all, a flipped face is out of the question */
204     if (is_quad_flip_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) {
205       goto fail;
206     }
207     else {
208       float edge_vecs[4][3];
209 
210       sub_v3_v3v3(edge_vecs[0], verts[0]->co, verts[1]->co);
211       sub_v3_v3v3(edge_vecs[1], verts[1]->co, verts[2]->co);
212       sub_v3_v3v3(edge_vecs[2], verts[2]->co, verts[3]->co);
213       sub_v3_v3v3(edge_vecs[3], verts[3]->co, verts[0]->co);
214 
215       normalize_v3(edge_vecs[0]);
216       normalize_v3(edge_vecs[1]);
217       normalize_v3(edge_vecs[2]);
218       normalize_v3(edge_vecs[3]);
219 
220       if ((fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) >
221            delimit_data->angle_shape) ||
222           (fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) >
223            delimit_data->angle_shape) ||
224           (fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) >
225            delimit_data->angle_shape) ||
226           (fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2) >
227            delimit_data->angle_shape)) {
228         goto fail;
229       }
230     }
231   }
232 
233   if (delimit_data->cdata_len) {
234     int i;
235     for (i = 0; i < delimit_data->cdata_len; i++) {
236       if (!bm_edge_is_contiguous_loop_cd_all(e, &delimit_data->cdata[i])) {
237         goto fail;
238       }
239     }
240   }
241 
242   return false;
243 
244 fail:
245   return true;
246 }
247 
248 #define EDGE_MARK (1 << 0)
249 
250 #define FACE_OUT (1 << 0)
251 #define FACE_INPUT (1 << 2)
252 
bmo_join_triangles_exec(BMesh * bm,BMOperator * op)253 void bmo_join_triangles_exec(BMesh *bm, BMOperator *op)
254 {
255   float angle_face, angle_shape;
256 
257   BMIter iter;
258   BMOIter siter;
259   BMFace *f;
260   BMEdge *e;
261   /* data: edge-to-join, sort_value: error weight */
262   struct SortPtrByFloat *jedges;
263   uint i, totedge;
264   uint totedge_tag = 0;
265 
266   struct DelimitData delimit_data = {0};
267 
268   delimit_data.do_seam = BMO_slot_bool_get(op->slots_in, "cmp_seam");
269   delimit_data.do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp");
270   delimit_data.do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials");
271 
272   angle_face = BMO_slot_float_get(op->slots_in, "angle_face_threshold");
273   if (angle_face < DEG2RADF(180.0f)) {
274     delimit_data.angle_face = angle_face;
275     delimit_data.angle_face__cos = cosf(angle_face);
276     delimit_data.do_angle_face = true;
277   }
278   else {
279     delimit_data.do_angle_face = false;
280   }
281 
282   angle_shape = BMO_slot_float_get(op->slots_in, "angle_shape_threshold");
283   if (angle_shape < DEG2RADF(180.0f)) {
284     delimit_data.angle_shape = angle_shape;
285     delimit_data.do_angle_shape = true;
286   }
287   else {
288     delimit_data.do_angle_shape = false;
289   }
290 
291   if (BMO_slot_bool_get(op->slots_in, "cmp_uvs") &&
292       bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPUV, &delimit_data.cdata[delimit_data.cdata_len])) {
293     delimit_data.cdata_len += 1;
294   }
295 
296   delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1;
297   if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") &&
298       bm_edge_delimit_cdata(
299           &bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len])) {
300     delimit_data.cdata_len += 1;
301   }
302 
303   /* flag all edges of all input face */
304   BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
305     if (f->len == 3) {
306       BMO_face_flag_enable(bm, f, FACE_INPUT);
307     }
308   }
309 
310   /* flag edges surrounded by 2 flagged triangles */
311   BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
312     BMFace *f_a, *f_b;
313     if (BM_edge_face_pair(e, &f_a, &f_b) &&
314         (BMO_face_flag_test(bm, f_a, FACE_INPUT) && BMO_face_flag_test(bm, f_b, FACE_INPUT))) {
315       if (!bm_edge_is_delimit(e, &delimit_data)) {
316         BMO_edge_flag_enable(bm, e, EDGE_MARK);
317         totedge_tag++;
318       }
319     }
320   }
321 
322   if (totedge_tag == 0) {
323     return;
324   }
325 
326   /* over alloc, some of the edges will be delimited */
327   jedges = MEM_mallocN(sizeof(*jedges) * totedge_tag, __func__);
328 
329   i = 0;
330   BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
331     const BMVert *verts[4];
332     float error;
333 
334     if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) {
335       continue;
336     }
337 
338     bm_edge_to_quad_verts(e, verts);
339 
340     error = quad_calc_error(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co);
341 
342     jedges[i].data = e;
343     jedges[i].sort_value = error;
344     i++;
345   }
346 
347   totedge = i;
348   qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float);
349 
350   for (i = 0; i < totedge; i++) {
351     BMLoop *l_a, *l_b;
352 
353     e = jedges[i].data;
354     l_a = e->l;
355     l_b = e->l->radial_next;
356 
357     /* check if another edge already claimed this face */
358     if ((l_a->f->len == 3) && (l_b->f->len == 3)) {
359       BMFace *f_new;
360       f_new = BM_faces_join_pair(bm, l_a, l_b, true);
361       if (f_new) {
362         BMO_face_flag_enable(bm, f_new, FACE_OUT);
363       }
364     }
365   }
366 
367   MEM_freeN(jedges);
368 
369   BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT);
370 }
371