Blender  V2.93
bmo_connect_nonplanar.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 "BLI_alloca.h"
24 #include "BLI_linklist_stack.h"
25 #include "BLI_math.h"
26 #include "BLI_utildefines.h"
27 
28 #include "bmesh.h"
29 
30 #include "intern/bmesh_operators_private.h" /* own include */
31 
32 #define EDGE_OUT (1 << 0)
33 #define FACE_OUT (1 << 1)
34 
38 static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const float no[3])
39 {
40  float axis_mat[3][3];
41  float z_prev, z_curr;
42  float delta_z = 0.0f;
43 
44  /* Newell's Method */
45  BMLoop *l_iter = l_first;
46  BMLoop *l_term = l_last->next;
47 
48  axis_dominant_v3_to_m3(axis_mat, no);
49 
50  z_prev = dot_m3_v3_row_z(axis_mat, l_last->v->co);
51  do {
52  z_curr = dot_m3_v3_row_z(axis_mat, l_iter->v->co);
53  delta_z += fabsf(z_curr - z_prev);
54  z_prev = z_curr;
55  } while ((l_iter = l_iter->next) != l_term);
56 
57  return delta_z;
58 }
59 
60 static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle_cos)
61 {
62  BMLoop *l_iter, *l_first;
63  BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
64  const uint f_len = f->len;
65  uint i_a, i_b;
66  bool found = false;
67 
68  /* angle finding */
69  float err_best = FLT_MAX;
70  float angle_best_cos = -FLT_MAX;
71 
72  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
73  i_a = 0;
74  do {
75  l_arr[i_a++] = l_iter;
76  } while ((l_iter = l_iter->next) != l_first);
77 
78  /* now for the big search, O(N^2), however faces normally aren't so large */
79  for (i_a = 0; i_a < f_len; i_a++) {
80  BMLoop *l_a = l_arr[i_a];
81  for (i_b = i_a + 2; i_b < f_len; i_b++) {
82  BMLoop *l_b = l_arr[i_b];
83  /* check these are not touching
84  * (we could be smarter here) */
85  if (!BM_loop_is_adjacent(l_a, l_b)) {
86  /* first calculate normals */
87  float no_a[3], no_b[3];
88 
89  if (BM_face_calc_normal_subset(l_a, l_b, no_a) != 0.0f &&
90  BM_face_calc_normal_subset(l_b, l_a, no_b) != 0.0f) {
91  const float err_a = bm_face_subset_calc_planar(l_a, l_b, no_a);
92  const float err_b = bm_face_subset_calc_planar(l_b, l_a, no_b);
93  const float err_test = err_a + err_b;
94 
95  if (err_test < err_best) {
96  /* check we're legal (we could batch this) */
97  BMLoop *l_split[2] = {l_a, l_b};
98  BM_face_splits_check_legal(bm, f, &l_split, 1);
99  if (l_split[0]) {
100  err_best = err_test;
101  l_pair[0] = l_a;
102  l_pair[1] = l_b;
103 
104  angle_best_cos = dot_v3v3(no_a, no_b);
105  found = true;
106  }
107  }
108  }
109  }
110  }
111  }
112 
113  *r_angle_cos = angle_best_cos;
114 
115  return found;
116 }
117 
119  BMFace *f,
120  BMFace *r_f_pair[2],
121  const float angle_limit_cos)
122 {
123  BMLoop *l_pair[2];
124  float angle_cos;
125 
126  if (bm_face_split_find(bm, f, l_pair, &angle_cos) && (angle_cos < angle_limit_cos)) {
127  BMFace *f_new;
128  BMLoop *l_new;
129 
130  f_new = BM_face_split(bm, f, l_pair[0], l_pair[1], &l_new, NULL, false);
131  if (f_new) {
132  r_f_pair[0] = f;
133  r_f_pair[1] = f_new;
134 
137  BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT);
138  return true;
139  }
140  }
141 
142  return false;
143 }
144 
146 {
147  BMOIter siter;
148  BMFace *f;
149  bool changed = false;
150  BLI_LINKSTACK_DECLARE(fstack, BMFace *);
151 
152  const float angle_limit_cos = cosf(BMO_slot_float_get(op->slots_in, "angle_limit"));
153 
154  BLI_LINKSTACK_INIT(fstack);
155 
156  BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
157  if (f->len > 3) {
158  BLI_LINKSTACK_PUSH(fstack, f);
159  }
160  }
161 
162  while ((f = BLI_LINKSTACK_POP(fstack))) {
163  BMFace *f_pair[2];
164  if (bm_face_split_by_angle(bm, f, f_pair, angle_limit_cos)) {
165  int j;
166  for (j = 0; j < 2; j++) {
167  BM_face_normal_update(f_pair[j]);
168  if (f_pair[j]->len > 3) {
169  BLI_LINKSTACK_PUSH(fstack, f_pair[j]);
170  }
171  }
172  changed = true;
173  }
174  }
175 
176  BLI_LINKSTACK_FREE(fstack);
177 
178  if (changed) {
181  }
182 }
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3752
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:83
@ 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
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
Definition: bmesh_mods.c:252
#define BMO_edge_flag_enable(bm, e, oflag)
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag)
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
void BM_face_normal_update(BMFace *f)
float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle_cos)
#define FACE_OUT
#define EDGE_OUT
void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const float no[3])
static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit_cos)
#define cosf(x)
#define fabsf(x)
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
uint len