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 * Beautify the mesh by rotating edges between triangles
21 * to more attractive positions until no more rotations can be made.
22 *
23 * In principle this is very simple however there is the possibility of
24 * going into an eternal loop where edges keep rotating.
25 * To avoid this - each edge stores a set of it previous
26 * states so as not to rotate back.
27 *
28 * TODO
29 * - Take face normals into account.
30 */
31
32 #include "BLI_heap.h"
33 #include "BLI_math.h"
34 #include "BLI_polyfill_2d_beautify.h"
35
36 #include "MEM_guardedalloc.h"
37
38 #include "bmesh.h"
39 #include "bmesh_beautify.h" /* own include */
40
41 // #define DEBUG_TIME
42
43 #ifdef DEBUG_TIME
44 # include "PIL_time.h"
45 # include "PIL_time_utildefines.h"
46 #endif
47
48 /* -------------------------------------------------------------------- */
49 /* GSet for edge rotation */
50
51 typedef struct EdRotState {
52 int v1, v2; /* edge vert, small -> large */
53 int f1, f2; /* face vert, small -> large */
54 } EdRotState;
55
56 #if 0
57 /* use BLI_ghashutil_inthash_v4 direct */
58 static uint erot_gsetutil_hash(const void *ptr)
59 {
60 const EdRotState *e_state = (const EdRotState *)ptr;
61 return BLI_ghashutil_inthash_v4(&e_state->v1);
62 }
63 #endif
64 #if 0
65 static int erot_gsetutil_cmp(const void *a, const void *b)
66 {
67 const EdRotState *e_state_a = (const EdRotState *)a;
68 const EdRotState *e_state_b = (const EdRotState *)b;
69 if (e_state_a->v1 < e_state_b->v1) {
70 return -1;
71 }
72 else if (e_state_a->v1 > e_state_b->v1) {
73 return 1;
74 }
75 else if (e_state_a->v2 < e_state_b->v2) {
76 return -1;
77 }
78 else if (e_state_a->v2 > e_state_b->v2) {
79 return 1;
80 }
81 else if (e_state_a->f1 < e_state_b->f1) {
82 return -1;
83 }
84 else if (e_state_a->f1 > e_state_b->f1) {
85 return 1;
86 }
87 else if (e_state_a->f2 < e_state_b->f2) {
88 return -1;
89 }
90 else if (e_state_a->f2 > e_state_b->f2) {
91 return 1;
92 }
93 else {
94 return 0;
95 }
96 }
97 #endif
erot_gset_new(void)98 static GSet *erot_gset_new(void)
99 {
100 return BLI_gset_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
101 }
102
103 /* ensure v0 is smaller */
104 #define EDGE_ORD(v0, v1) \
105 if (v0 > v1) { \
106 SWAP(int, v0, v1); \
107 } \
108 (void)0
109
erot_state_ex(const BMEdge * e,int v_index[2],int f_index[2])110 static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2])
111 {
112 BLI_assert(BM_edge_is_manifold(e));
113 BLI_assert(BM_vert_in_edge(e, e->l->prev->v) == false);
114 BLI_assert(BM_vert_in_edge(e, e->l->radial_next->prev->v) == false);
115
116 /* verts of the edge */
117 v_index[0] = BM_elem_index_get(e->v1);
118 v_index[1] = BM_elem_index_get(e->v2);
119 EDGE_ORD(v_index[0], v_index[1]);
120
121 /* verts of each of the 2 faces attached to this edge
122 * (that are not a part of this edge) */
123 f_index[0] = BM_elem_index_get(e->l->prev->v);
124 f_index[1] = BM_elem_index_get(e->l->radial_next->prev->v);
125 EDGE_ORD(f_index[0], f_index[1]);
126 }
127
erot_state_current(const BMEdge * e,EdRotState * e_state)128 static void erot_state_current(const BMEdge *e, EdRotState *e_state)
129 {
130 erot_state_ex(e, &e_state->v1, &e_state->f1);
131 }
132
erot_state_alternate(const BMEdge * e,EdRotState * e_state)133 static void erot_state_alternate(const BMEdge *e, EdRotState *e_state)
134 {
135 erot_state_ex(e, &e_state->f1, &e_state->v1);
136 }
137
138 /* -------------------------------------------------------------------- */
139 /* Calculate the improvement of rotating the edge */
140
bm_edge_calc_rotate_beauty__area(const float v1[3],const float v2[3],const float v3[3],const float v4[3],const bool lock_degenerate)141 static float bm_edge_calc_rotate_beauty__area(const float v1[3],
142 const float v2[3],
143 const float v3[3],
144 const float v4[3],
145 const bool lock_degenerate)
146 {
147 /* not a loop (only to be able to break out) */
148 do {
149 float v1_xy[2], v2_xy[2], v3_xy[2], v4_xy[2];
150
151 /* first get the 2d values */
152 {
153 const float eps = 1e-5;
154 float no_a[3], no_b[3];
155 float no[3];
156 float axis_mat[3][3];
157 float no_scale;
158 cross_tri_v3(no_a, v2, v3, v4);
159 cross_tri_v3(no_b, v2, v4, v1);
160
161 // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f);
162 BLI_assert((ELEM(v1, v2, v3, v4) == false) && (ELEM(v2, v1, v3, v4) == false) &&
163 (ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false));
164
165 add_v3_v3v3(no, no_a, no_b);
166 if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) {
167 break;
168 }
169
170 axis_dominant_v3_to_m3(axis_mat, no);
171 mul_v2_m3v3(v1_xy, axis_mat, v1);
172 mul_v2_m3v3(v2_xy, axis_mat, v2);
173 mul_v2_m3v3(v3_xy, axis_mat, v3);
174 mul_v2_m3v3(v4_xy, axis_mat, v4);
175
176 /**
177 * Check if input faces are already flipped.
178 * Logic for 'signum_i' addition is:
179 *
180 * Accept:
181 * - (1, 1) or (-1, -1): same side (common case).
182 * - (-1/1, 0): one degenerate, OK since we may rotate into a valid state.
183 *
184 * Ignore:
185 * - (-1, 1): opposite winding, ignore.
186 * - ( 0, 0): both degenerate, ignore.
187 *
188 * \note The cross product is divided by 'no_scale'
189 * so the rotation calculation is scale independent.
190 */
191 if (!(signum_i_ex(cross_tri_v2(v2_xy, v3_xy, v4_xy) / no_scale, eps) +
192 signum_i_ex(cross_tri_v2(v2_xy, v4_xy, v1_xy) / no_scale, eps))) {
193 break;
194 }
195 }
196
197 /**
198 * Important to lock degenerate here,
199 * since the triangle pars will be projected into different 2D spaces.
200 * Allowing to rotate out of a degenerate state can flip the faces
201 * (when performed iteratively).
202 */
203 return BLI_polyfill_beautify_quad_rotate_calc_ex(
204 v1_xy, v2_xy, v3_xy, v4_xy, lock_degenerate, NULL);
205 } while (false);
206
207 return FLT_MAX;
208 }
209
bm_edge_calc_rotate_beauty__angle(const float v1[3],const float v2[3],const float v3[3],const float v4[3])210 static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
211 const float v2[3],
212 const float v3[3],
213 const float v4[3])
214 {
215 /* not a loop (only to be able to break out) */
216 do {
217 float no_a[3], no_b[3];
218 float angle_24, angle_13;
219
220 /* edge (2-4), current state */
221 normal_tri_v3(no_a, v2, v3, v4);
222 normal_tri_v3(no_b, v2, v4, v1);
223 angle_24 = angle_normalized_v3v3(no_a, no_b);
224
225 /* edge (1-3), new state */
226 /* only check new state for degenerate outcome */
227 if ((normal_tri_v3(no_a, v1, v2, v3) == 0.0f) || (normal_tri_v3(no_b, v1, v3, v4) == 0.0f)) {
228 break;
229 }
230 angle_13 = angle_normalized_v3v3(no_a, no_b);
231
232 return angle_13 - angle_24;
233 } while (false);
234
235 return FLT_MAX;
236 }
237
238 /**
239 * Assuming we have 2 triangles sharing an edge (2 - 4),
240 * check if the edge running from (1 - 3) gives better results.
241 *
242 * \return (negative number means the edge can be rotated, lager == better).
243 */
BM_verts_calc_rotate_beauty(const BMVert * v1,const BMVert * v2,const BMVert * v3,const BMVert * v4,const short flag,const short method)244 float BM_verts_calc_rotate_beauty(const BMVert *v1,
245 const BMVert *v2,
246 const BMVert *v3,
247 const BMVert *v4,
248 const short flag,
249 const short method)
250 {
251 /* not a loop (only to be able to break out) */
252 do {
253 if (flag & VERT_RESTRICT_TAG) {
254 const BMVert *v_a = v1, *v_b = v3;
255 if (BM_elem_flag_test(v_a, BM_ELEM_TAG) == BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
256 break;
257 }
258 }
259
260 if (UNLIKELY(v1 == v3)) {
261 // printf("This should never happen, but does sometimes!\n");
262 break;
263 }
264
265 switch (method) {
266 case 0:
267 return bm_edge_calc_rotate_beauty__area(
268 v1->co, v2->co, v3->co, v4->co, flag & EDGE_RESTRICT_DEGENERATE);
269 default:
270 return bm_edge_calc_rotate_beauty__angle(v1->co, v2->co, v3->co, v4->co);
271 }
272 } while (false);
273
274 return FLT_MAX;
275 }
276
bm_edge_calc_rotate_beauty(const BMEdge * e,const short flag,const short method)277 static float bm_edge_calc_rotate_beauty(const BMEdge *e, const short flag, const short method)
278 {
279 const BMVert *v1, *v2, *v3, *v4;
280 v1 = e->l->prev->v; /* first vert co */
281 v2 = e->l->v; /* e->v1 or e->v2*/
282 v3 = e->l->radial_next->prev->v; /* second vert co */
283 v4 = e->l->next->v; /* e->v1 or e->v2*/
284
285 return BM_verts_calc_rotate_beauty(v1, v2, v3, v4, flag, method);
286 }
287
288 /* -------------------------------------------------------------------- */
289 /* Update the edge cost of rotation in the heap */
290
edge_in_array(const BMEdge * e,const BMEdge ** edge_array,const int edge_array_len)291 BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const int edge_array_len)
292 {
293 const int index = BM_elem_index_get(e);
294 return ((index >= 0) && (index < edge_array_len) && (e == edge_array[index]));
295 }
296
297 /* recalc an edge in the heap (surrounding geometry has changed) */
bm_edge_update_beauty_cost_single(BMEdge * e,Heap * eheap,HeapNode ** eheap_table,GSet ** edge_state_arr,const BMEdge ** edge_array,const int edge_array_len,const short flag,const short method)298 static void bm_edge_update_beauty_cost_single(BMEdge *e,
299 Heap *eheap,
300 HeapNode **eheap_table,
301 GSet **edge_state_arr,
302 /* only for testing the edge is in the array */
303 const BMEdge **edge_array,
304 const int edge_array_len,
305
306 const short flag,
307 const short method)
308 {
309 if (edge_in_array(e, edge_array, edge_array_len)) {
310 const int i = BM_elem_index_get(e);
311 GSet *e_state_set = edge_state_arr[i];
312
313 if (eheap_table[i]) {
314 BLI_heap_remove(eheap, eheap_table[i]);
315 eheap_table[i] = NULL;
316 }
317
318 /* check if we can add it back */
319 BLI_assert(BM_edge_is_manifold(e) == true);
320
321 /* check we're not moving back into a state we have been in before */
322 if (e_state_set != NULL) {
323 EdRotState e_state_alt;
324 erot_state_alternate(e, &e_state_alt);
325 if (BLI_gset_haskey(e_state_set, (void *)&e_state_alt)) {
326 // printf(" skipping, we already have this state\n");
327 return;
328 }
329 }
330
331 {
332 /* recalculate edge */
333 const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
334 if (cost < 0.0f) {
335 eheap_table[i] = BLI_heap_insert(eheap, cost, e);
336 }
337 else {
338 eheap_table[i] = NULL;
339 }
340 }
341 }
342 }
343
344 /* we have rotated an edge, tag other edges and clear this one */
bm_edge_update_beauty_cost(BMEdge * e,Heap * eheap,HeapNode ** eheap_table,GSet ** edge_state_arr,const BMEdge ** edge_array,const int edge_array_len,const short flag,const short method)345 static void bm_edge_update_beauty_cost(BMEdge *e,
346 Heap *eheap,
347 HeapNode **eheap_table,
348 GSet **edge_state_arr,
349 const BMEdge **edge_array,
350 const int edge_array_len,
351 /* only for testing the edge is in the array */
352 const short flag,
353 const short method)
354 {
355 int i;
356
357 BMEdge *e_arr[4] = {
358 e->l->next->e,
359 e->l->prev->e,
360 e->l->radial_next->next->e,
361 e->l->radial_next->prev->e,
362 };
363
364 BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3);
365
366 BLI_assert(BM_edge_face_count_is_equal(e, 2));
367
368 for (i = 0; i < 4; i++) {
369 bm_edge_update_beauty_cost_single(
370 e_arr[i], eheap, eheap_table, edge_state_arr, edge_array, edge_array_len, flag, method);
371 }
372 }
373
374 /* -------------------------------------------------------------------- */
375 /* Beautify Fill */
376
377 /**
378 * \note This function sets the edge indices to invalid values.
379 */
BM_mesh_beautify_fill(BMesh * bm,BMEdge ** edge_array,const int edge_array_len,const short flag,const short method,const short oflag_edge,const short oflag_face)380 void BM_mesh_beautify_fill(BMesh *bm,
381 BMEdge **edge_array,
382 const int edge_array_len,
383 const short flag,
384 const short method,
385 const short oflag_edge,
386 const short oflag_face)
387 {
388 Heap *eheap; /* edge heap */
389 HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
390
391 GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__);
392 BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP);
393 int i;
394
395 #ifdef DEBUG_TIME
396 TIMEIT_START(beautify_fill);
397 #endif
398
399 eheap = BLI_heap_new_ex((uint)edge_array_len);
400 eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__);
401
402 /* build heap */
403 for (i = 0; i < edge_array_len; i++) {
404 BMEdge *e = edge_array[i];
405 const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
406 if (cost < 0.0f) {
407 eheap_table[i] = BLI_heap_insert(eheap, cost, e);
408 }
409 else {
410 eheap_table[i] = NULL;
411 }
412
413 BM_elem_index_set(e, i); /* set_dirty */
414 }
415 bm->elem_index_dirty |= BM_EDGE;
416
417 while (BLI_heap_is_empty(eheap) == false) {
418 BMEdge *e = BLI_heap_pop_min(eheap);
419 i = BM_elem_index_get(e);
420 eheap_table[i] = NULL;
421
422 BLI_assert(BM_edge_face_count_is_equal(e, 2));
423
424 e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS);
425
426 BLI_assert(e == NULL || BM_edge_face_count_is_equal(e, 2));
427
428 if (LIKELY(e)) {
429 GSet *e_state_set = edge_state_arr[i];
430
431 /* add the new state into the set so we don't move into this state again
432 * note: we could add the previous state too but this isn't essential)
433 * for avoiding eternal loops */
434 EdRotState *e_state = BLI_mempool_alloc(edge_state_pool);
435 erot_state_current(e, e_state);
436 if (UNLIKELY(e_state_set == NULL)) {
437 edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */
438 }
439 BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false);
440 BLI_gset_insert(e_state_set, e_state);
441
442 // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2));
443
444 /* maintain the index array */
445 edge_array[i] = e;
446 BM_elem_index_set(e, i);
447
448 /* recalculate faces connected on the heap */
449 bm_edge_update_beauty_cost(e,
450 eheap,
451 eheap_table,
452 edge_state_arr,
453 (const BMEdge **)edge_array,
454 edge_array_len,
455 flag,
456 method);
457
458 /* update flags */
459 if (oflag_edge) {
460 BMO_edge_flag_enable(bm, e, oflag_edge);
461 }
462
463 if (oflag_face) {
464 BMO_face_flag_enable(bm, e->l->f, oflag_face);
465 BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face);
466 }
467 }
468 }
469
470 BLI_heap_free(eheap, NULL);
471 MEM_freeN(eheap_table);
472
473 for (i = 0; i < edge_array_len; i++) {
474 if (edge_state_arr[i]) {
475 BLI_gset_free(edge_state_arr[i], NULL);
476 }
477 }
478
479 MEM_freeN(edge_state_arr);
480 BLI_mempool_destroy(edge_state_pool);
481
482 #ifdef DEBUG_TIME
483 TIMEIT_END(beautify_fill);
484 #endif
485 }
486