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