doxygen: add newline after \file
[blender.git] / source / blender / bmesh / operators / bmo_planar_faces.c
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  * Iteratively flatten 4+ sided faces.
21  */
22
23 #include "MEM_guardedalloc.h"
24
25 #include "BLI_math.h"
26 #include "BLI_ghash.h"
27
28 #include "bmesh.h"
29
30 #include "intern/bmesh_operators_private.h" /* own include */
31
32 #define ELE_VERT_ADJUST (1 << 0)
33 #define ELE_FACE_ADJUST (1 << 1)
34
35 struct VertAccum {
36         float co[3];
37         int co_tot;
38 };
39
40 void bmo_planar_faces_exec(BMesh *bm, BMOperator *op)
41 {
42         const float fac = BMO_slot_float_get(op->slots_in, "factor");
43         const int iterations = BMO_slot_int_get(op->slots_in, "iterations");
44         const int faces_num = BMO_slot_buffer_count(op->slots_in, "faces");
45
46         const float eps = 0.00001f;
47         const float eps_sq = SQUARE(eps);
48
49         BMOIter oiter;
50         BMFace *f;
51         BLI_mempool *vert_accum_pool;
52         GHash *vaccum_map;
53         float (*faces_center)[3];
54         int i, iter_step, shared_vert_num;
55
56         faces_center = MEM_mallocN(sizeof(*faces_center) * faces_num, __func__);
57
58         shared_vert_num = 0;
59         BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) {
60                 BMLoop *l_iter, *l_first;
61
62                 if (f->len == 3) {
63                         continue;
64                 }
65
66                 BM_face_calc_center_median_weighted(f, faces_center[i]);
67
68                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
69                 do {
70                         if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) {
71                                 BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST);
72                                 shared_vert_num += 1;
73                         }
74                 } while ((l_iter = l_iter->next) != l_first);
75
76                 BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST);
77         }
78
79         vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP);
80         vaccum_map = BLI_ghash_ptr_new_ex(__func__, shared_vert_num);
81
82         for (iter_step = 0; iter_step < iterations; iter_step++) {
83                 GHashIterator gh_iter;
84                 bool changed = false;
85
86                 BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) {
87                         BMLoop *l_iter, *l_first;
88                         float plane[4];
89
90                         if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) {
91                                 continue;
92                         }
93                         BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST);
94
95                         BLI_assert(f->len != 3);
96
97                         /* keep original face data (else we 'move' the face) */
98 #if 0
99                         BM_face_normal_update(f);
100                         BM_face_calc_center_median_weighted(f, f_center);
101 #endif
102
103                         plane_from_point_normal_v3(plane, faces_center[i], f->no);
104
105                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
106                         do {
107                                 struct VertAccum *va;
108                                 void **va_p;
109                                 float co[3];
110
111                                 if (!BLI_ghash_ensure_p(vaccum_map, l_iter->v, &va_p)) {
112                                         *va_p = BLI_mempool_calloc(vert_accum_pool);
113                                 }
114                                 va = *va_p;
115
116                                 closest_to_plane_normalized_v3(co, plane, l_iter->v->co);
117                                 va->co_tot += 1;
118
119                                 interp_v3_v3v3(va->co, va->co, co, 1.0f / (float)va->co_tot);
120                         } while ((l_iter = l_iter->next) != l_first);
121                 }
122
123                 GHASH_ITER (gh_iter, vaccum_map) {
124                         BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
125                         struct VertAccum *va = BLI_ghashIterator_getValue(&gh_iter);
126                         BMIter iter;
127
128                         if (len_squared_v3v3(v->co, va->co) > eps_sq) {
129                                 BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST);
130                                 interp_v3_v3v3(v->co, v->co, va->co, fac);
131                                 changed = true;
132                         }
133
134                         /* tag for re-calculation */
135                         BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
136                                 if (f->len != 3) {
137                                         BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST);
138                                 }
139                         }
140                 }
141
142                 /* if nothing changed, break out early */
143                 if (changed == false) {
144                         break;
145                 }
146
147                 BLI_ghash_clear(vaccum_map, NULL, NULL);
148                 BLI_mempool_clear(vert_accum_pool);
149         }
150
151         MEM_freeN(faces_center);
152         BLI_ghash_free(vaccum_map, NULL, NULL);
153         BLI_mempool_destroy(vert_accum_pool);
154 }