Blender  V2.93
bmo_normals.c
Go to the documentation of this file.
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 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_linklist_stack.h"
26 #include "BLI_math.h"
27 
28 #include "bmesh.h"
29 
30 #include "intern/bmesh_operators_private.h" /* own include */
31 
32 /********* Right-hand faces implementation ****** */
33 
34 #define FACE_FLAG (1 << 0)
35 #define FACE_FLIP (1 << 1)
36 #define FACE_TEMP (1 << 2)
37 
39 {
40  return BM_edge_is_manifold(l->e);
41 }
42 
75  BMFace **faces,
76  const int faces_len,
77  bool *r_is_flip)
78 {
79  const float eps = FLT_EPSILON;
80  float cent_area_accum = 0.0f;
81  float cent[3];
82  const float cent_fac = 1.0f / (float)faces_len;
83 
84  bool is_flip = false;
85  int f_start_index;
86  int i;
87 
89  struct {
95  float dist_sq;
100  float edge_dot;
105  float loop_dot;
106  } best, test;
107 
109 
110  zero_v3(cent);
111 
112  /* first calculate the center */
113  for (i = 0; i < faces_len; i++) {
114  float f_cent[3];
115  const float f_area = BM_face_calc_area(faces[i]);
117  madd_v3_v3fl(cent, f_cent, cent_fac * f_area);
118  cent_area_accum += f_area;
119 
122  }
123 
124  if (cent_area_accum != 0.0f) {
125  mul_v3_fl(cent, 1.0f / cent_area_accum);
126  }
127 
128  /* Distances must start above zero,
129  * or we can't do meaningful calculations based on the direction to the center */
130  best.dist_sq = eps;
131  best.edge_dot = best.loop_dot = -FLT_MAX;
132 
133  /* used in degenerate cases only */
134  f_start_index = 0;
135 
144  for (i = 0; i < faces_len; i++) {
145  BMLoop *l_iter, *l_first;
146 
147  l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]);
148  do {
149  bool is_best_dist_sq;
150  float dir[3];
151  sub_v3_v3v3(dir, l_iter->v->co, cent);
152  test.dist_sq = len_squared_v3(dir);
153  is_best_dist_sq = (test.dist_sq > best.dist_sq);
154  if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) {
155  float edge_dir_pair[2][3];
156  mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq));
157 
158  sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co);
159  sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co);
160 
161  if ((normalize_v3(edge_dir_pair[0]) > eps) && (normalize_v3(edge_dir_pair[1]) > eps)) {
162  bool is_best_edge_dot;
163  test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]), dot_v3v3(dir, edge_dir_pair[1]));
164  is_best_edge_dot = (test.edge_dot > best.edge_dot);
165  if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) {
166  float loop_dir[3];
167  cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]);
168  if (normalize_v3(loop_dir) > eps) {
169  float loop_dir_dot;
170  /* Highly unlikely the furthest loop is also the concave part of an ngon,
171  * but it can be contrived with _very_ non-planar faces - so better check. */
172  if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) {
173  negate_v3(loop_dir);
174  }
175  loop_dir_dot = dot_v3v3(dir, loop_dir);
176  test.loop_dot = fabsf(loop_dir_dot);
177  if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) {
178  best = test;
179  f_start_index = i;
180  is_flip = (loop_dir_dot < 0.0f);
181  }
182  }
183  }
184  }
185  }
186  } while ((l_iter = l_iter->next) != l_first);
187  }
188 
189  *r_is_flip = is_flip;
190  return f_start_index;
191 }
192 
203  BMFace **faces,
204  const int faces_len,
205  const short oflag)
206 {
207  int i, f_start_index;
208  const short oflag_flip = oflag | FACE_FLIP;
209  bool is_flip;
210 
211  BMFace *f;
212 
213  BLI_LINKSTACK_DECLARE(fstack, BMFace *);
214 
215  f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip);
216 
217  if (is_flip) {
218  BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP);
219  }
220 
221  /* now that we've found our starting face, make all connected faces
222  * have the same winding. this is done recursively, using a manual
223  * stack (if we use simple function recursion, we'd end up overloading
224  * the stack on large meshes). */
225  BLI_LINKSTACK_INIT(fstack);
226 
227  BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]);
228  BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP);
229 
230  while ((f = BLI_LINKSTACK_POP(fstack))) {
231  const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP);
232  BMLoop *l_iter, *l_first;
233 
234  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
235  do {
236  BMLoop *l_other = l_iter->radial_next;
237 
238  if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) {
239  if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) {
240  BMO_face_flag_enable(bm, l_other->f, FACE_TEMP);
241  BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
242  BLI_LINKSTACK_PUSH(fstack, l_other->f);
243  }
244  }
245  } while ((l_iter = l_iter->next) != l_first);
246  }
247 
248  BLI_LINKSTACK_FREE(fstack);
249 
250  /* apply flipping to oflag'd faces */
251  for (i = 0; i < faces_len; i++) {
252  if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) {
254  }
256  }
257 }
258 
269 {
270  int *groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totface, __func__);
271  BMFace **faces_grp = MEM_mallocN(sizeof(*faces_grp) * bm->totface, __func__);
272 
273  int(*group_index)[2];
274  const int group_tot = BM_mesh_calc_face_groups(
275  bm, groups_array, &group_index, bmo_recalc_normal_loop_filter_cb, NULL, NULL, 0, BM_EDGE);
276  int i;
277 
279 
281 
282  for (i = 0; i < group_tot; i++) {
283  const int fg_sta = group_index[i][0];
284  const int fg_len = group_index[i][1];
285  int j;
286  bool is_calc = false;
287 
288  for (j = 0; j < fg_len; j++) {
289  faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
290 
291  if (is_calc == false) {
292  is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG);
293  }
294  }
295 
296  if (is_calc) {
297  bmo_recalc_face_normals_array(bm, faces_grp, fg_len, FACE_FLAG);
298  }
299  }
300 
301  MEM_freeN(faces_grp);
302 
303  MEM_freeN(groups_array);
304  MEM_freeN(group_index);
305 }
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float max_ff(float a, float b)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE void zero_v3(float r[3])
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_EDGE
Definition: bmesh_class.h:384
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag)
BMO_FLAG_BUFFER.
#define BMO_face_flag_test_bool(bm, e, oflag)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_face_flag_set(bm, e, oflag, val)
#define BMO_face_flag_disable(bm, e, oflag)
#define BMO_face_flag_test(bm, e, oflag)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
void BM_face_normal_flip(BMesh *bm, BMFace *f)
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMLoopFilterFunc filter_fn, BMLoopPairFilterFunc filter_pair_fn, void *user_data, const char hflag_test, const char htype_step)
Definition: bmesh_query.c:2611
bool BM_face_is_normal_valid(const BMFace *f)
Definition: bmesh_query.c:2533
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
#define FACE_FLAG
Definition: bmo_normals.c:34
#define FACE_TEMP
Definition: bmo_normals.c:36
static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_data))
Definition: bmo_normals.c:38
static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int faces_len, bool *r_is_flip)
Definition: bmo_normals.c:74
static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int faces_len, const short oflag)
Definition: bmo_normals.c:202
void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op)
Definition: bmo_normals.c:268
#define FACE_FLIP
Definition: bmo_normals.c:35
void * user_data
#define fabsf(x)
#define sqrtf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static char faces[256]
const btScalar eps
Definition: poly34.cpp:11
float no[3]
Definition: bmesh_class.h:280
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
int totface
Definition: bmesh_class.h:297