Blender  V2.93
bmo_fill_grid.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_listbase.h"
26 #include "BLI_math.h"
27 
28 #include "BKE_customdata.h"
29 
30 #include "bmesh.h"
31 
32 #include "intern/bmesh_operators_private.h" /* own include */
33 
34 #include "BLI_strict_flags.h"
35 
36 #define EDGE_MARK 4
37 #define FACE_OUT 16
38 
39 #define BARYCENTRIC_INTERP
40 
41 #ifdef BARYCENTRIC_INTERP
45 static void quad_edges_to_normal(float no[3],
46  const float co_a1[3],
47  const float co_a2[3],
48  const float co_b1[3],
49  const float co_b2[3])
50 {
51  float diff_a[3];
52  float diff_b[3];
53 
54  sub_v3_v3v3(diff_a, co_a2, co_a1);
55  sub_v3_v3v3(diff_b, co_b2, co_b1);
56  normalize_v3(diff_a);
57  normalize_v3(diff_b);
58  add_v3_v3v3(no, diff_a, diff_b);
59  normalize_v3(no);
60 }
61 
62 static void quad_verts_to_barycentric_tri(float tri[3][3],
63  const float co_a[3],
64  const float co_b[3],
65 
66  const float co_a_next[3],
67  const float co_b_next[3],
68 
69  const float co_a_prev[3],
70  const float co_b_prev[3],
71  const bool is_flip)
72 {
73  float no[3];
74 
75  copy_v3_v3(tri[0], co_a);
76  copy_v3_v3(tri[1], co_b);
77 
78  quad_edges_to_normal(no, co_a, co_a_next, co_b, co_b_next);
79 
80  if (co_a_prev) {
81  float no_t[3];
82  quad_edges_to_normal(no_t, co_a_prev, co_a, co_b_prev, co_b);
83  add_v3_v3(no, no_t);
84  normalize_v3(no);
85  }
86 
87  if (is_flip) {
88  negate_v3(no);
89  }
90  mul_v3_fl(no, len_v3v3(tri[0], tri[1]));
91 
92  mid_v3_v3v3(tri[2], tri[0], tri[1]);
93  add_v3_v3(tri[2], no);
94 }
95 
96 #endif
97 
98 /* -------------------------------------------------------------------- */
105 static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b, BMLoop *l_pair[2])
106 {
107  BMEdge *e = BM_edge_exists(v_a, v_b);
108  if (e->l) {
109  if (e->l->v == v_a) {
110  l_pair[0] = e->l;
111  l_pair[1] = e->l->next;
112  }
113  else {
114  l_pair[0] = e->l->next;
115  l_pair[1] = e->l;
116  }
117  }
118  else {
119  l_pair[0] = NULL;
120  l_pair[1] = NULL;
121  }
122 }
123 
129 static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2])
130 {
131  /* if the first one is set, we know the second is too */
132  if (l_pair_a[0] && l_pair_b[0] == NULL) {
133  l_pair_b[0] = l_pair_a[1];
134  l_pair_b[1] = l_pair_a[0];
135  }
136  else if (l_pair_b[0] && l_pair_a[0] == NULL) {
137  l_pair_a[0] = l_pair_b[1];
138  l_pair_a[1] = l_pair_b[0];
139  }
140 }
141 
148  BMLoop *l,
149  BMLoop *l_bound[4],
150  const float w[4])
151 {
152  const void *l_cdata[4] = {
153  l_bound[0]->head.data, l_bound[1]->head.data, l_bound[2]->head.data, l_bound[3]->head.data};
154 
155  CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 4, l->head.data);
156 }
157 
159  BMLoop *l,
160  BMLoop *l_bound[2],
161  const float t)
162 {
163  const void *l_cdata[2] = {l_bound[0]->head.data, l_bound[1]->head.data};
164 
165  const float w[2] = {1.0f - t, t};
166 
167  CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 2, l->head.data);
168 }
169 
176  const uint ytot,
177  float (*weight_table)[4])
178 {
179  float x_step = 1.0f / (float)(xtot - 1);
180  float y_step = 1.0f / (float)(ytot - 1);
181  uint i = 0;
182  float xy_fl[2];
183 
184  uint x, y;
185  for (y = 0; y < ytot; y++) {
186  xy_fl[1] = y_step * (float)y;
187  for (x = 0; x < xtot; x++) {
188  xy_fl[0] = x_step * (float)x;
189  {
190  const float cos[4][2] = {
191  {xy_fl[0], 0.0f}, {0.0f, xy_fl[1]}, {xy_fl[0], 1.0f}, {1.0f, xy_fl[1]}};
192  barycentric_weights_v2_quad(UNPACK4(cos), xy_fl, weight_table[i++]);
193  }
194  }
195  }
196 }
197 
204  BMVert **v_grid,
205  const uint xtot,
206  const uint ytot,
207  const short mat_nr,
208  const bool use_smooth,
209  const bool use_flip,
210  const bool use_interp_simple)
211 {
212  const bool use_vert_interp = CustomData_has_interp(&bm->vdata);
213  const bool use_loop_interp = CustomData_has_interp(&bm->ldata);
214  uint x, y;
215 
216  /* for use_loop_interp */
217  BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]);
218 
219  float(*weight_table)[4];
220 
221 #define XY(_x, _y) ((_x) + ((_y) * (xtot)))
222 
223 #ifdef BARYCENTRIC_INTERP
224  float tri_a[3][3];
225  float tri_b[3][3];
226  float tri_t[3][3]; /* temp */
227 
229  v_grid[XY(0, 0)]->co,
230  v_grid[XY(xtot - 1, 0)]->co,
231  v_grid[XY(0, 1)]->co,
232  v_grid[XY(xtot - 1, 1)]->co,
233  NULL,
234  NULL,
235  false);
236 
238  v_grid[XY(0, (ytot - 1))]->co,
239  v_grid[XY(xtot - 1, (ytot - 1))]->co,
240  v_grid[XY(0, (ytot - 2))]->co,
241  v_grid[XY(xtot - 1, (ytot - 2))]->co,
242  NULL,
243  NULL,
244  true);
245 #endif
246 
247  if (use_interp_simple || use_vert_interp || use_loop_interp) {
248  weight_table = MEM_mallocN(sizeof(*weight_table) * (size_t)(xtot * ytot), __func__);
249  barycentric_weights_v2_grid_cache(xtot, ytot, weight_table);
250  }
251  else {
252  weight_table = NULL;
253  }
254 
255  /* Store loops */
256  if (use_loop_interp) {
257  /* x2 because each edge connects 2 loops */
258  larr_x_a = MEM_mallocN(sizeof(*larr_x_a) * (xtot - 1), __func__);
259  larr_x_b = MEM_mallocN(sizeof(*larr_x_b) * (xtot - 1), __func__);
260 
261  larr_y_a = MEM_mallocN(sizeof(*larr_y_a) * (ytot - 1), __func__);
262  larr_y_b = MEM_mallocN(sizeof(*larr_y_b) * (ytot - 1), __func__);
263 
264  /* fill in the loops */
265  for (x = 0; x < xtot - 1; x++) {
266  bm_loop_pair_from_verts(v_grid[XY(x, 0)], v_grid[XY(x + 1, 0)], larr_x_a[x]);
267  bm_loop_pair_from_verts(v_grid[XY(x, ytot - 1)], v_grid[XY(x + 1, ytot - 1)], larr_x_b[x]);
268  bm_loop_pair_test_copy(larr_x_a[x], larr_x_b[x]);
269  }
270 
271  for (y = 0; y < ytot - 1; y++) {
272  bm_loop_pair_from_verts(v_grid[XY(0, y)], v_grid[XY(0, y + 1)], larr_y_a[y]);
273  bm_loop_pair_from_verts(v_grid[XY(xtot - 1, y)], v_grid[XY(xtot - 1, y + 1)], larr_y_b[y]);
274  bm_loop_pair_test_copy(larr_y_a[y], larr_y_b[y]);
275  }
276  }
277 
278  /* Build Verts */
279  for (y = 1; y < ytot - 1; y++) {
280 #ifdef BARYCENTRIC_INTERP
282  v_grid[XY(0, y + 0)]->co,
283  v_grid[XY(xtot - 1, y + 0)]->co,
284  v_grid[XY(0, y + 1)]->co,
285  v_grid[XY(xtot - 1, y + 1)]->co,
286  v_grid[XY(0, y - 1)]->co,
287  v_grid[XY(xtot - 1, y - 1)]->co,
288  false);
289 #endif
290  for (x = 1; x < xtot - 1; x++) {
291  float co[3];
292  BMVert *v;
293  /* we may want to allow sparse filled arrays, but for now, ensure its empty */
294  BLI_assert(v_grid[(y * xtot) + x] == NULL);
295 
296  /* place the vertex */
297 #ifdef BARYCENTRIC_INTERP
298  if (use_interp_simple == false) {
299  float co_a[3], co_b[3];
300 
302  co_a, v_grid[x]->co, tri_t[0], tri_t[1], tri_t[2], tri_a[0], tri_a[1], tri_a[2]);
304  v_grid[(xtot * ytot) + (x - xtot)]->co,
305  tri_t[0],
306  tri_t[1],
307  tri_t[2],
308  tri_b[0],
309  tri_b[1],
310  tri_b[2]);
311 
312  interp_v3_v3v3(co, co_a, co_b, (float)y / ((float)ytot - 1));
313  }
314  else
315 #endif
316  {
317  const float *w = weight_table[XY(x, y)];
318 
319  zero_v3(co);
320  madd_v3_v3fl(co, v_grid[XY(x, 0)]->co, w[0]);
321  madd_v3_v3fl(co, v_grid[XY(0, y)]->co, w[1]);
322  madd_v3_v3fl(co, v_grid[XY(x, ytot - 1)]->co, w[2]);
323  madd_v3_v3fl(co, v_grid[XY(xtot - 1, y)]->co, w[3]);
324  }
325 
327  v_grid[(y * xtot) + x] = v;
328 
329  /* Interpolate only along one axis, this could be changed
330  * but from user POV gives predictable results since these are selected loop. */
331  if (use_vert_interp) {
332  const float *w = weight_table[XY(x, y)];
333 
334  const void *v_cdata[4] = {
335  v_grid[XY(x, 0)]->head.data,
336  v_grid[XY(0, y)]->head.data,
337  v_grid[XY(x, ytot - 1)]->head.data,
338  v_grid[XY(xtot - 1, y)]->head.data,
339  };
340 
341  CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 4, v->head.data);
342  }
343  }
344  }
345 
346  /* Build Faces */
347  for (x = 0; x < xtot - 1; x++) {
348  for (y = 0; y < ytot - 1; y++) {
349  BMFace *f;
350 
351  if (use_flip) {
353  v_grid[XY(x, y + 0)], /* BL */
354  v_grid[XY(x, y + 1)], /* TL */
355  v_grid[XY(x + 1, y + 1)], /* TR */
356  v_grid[XY(x + 1, y + 0)], /* BR */
357  NULL,
358  BM_CREATE_NOP);
359  }
360  else {
362  v_grid[XY(x + 1, y + 0)], /* BR */
363  v_grid[XY(x + 1, y + 1)], /* TR */
364  v_grid[XY(x, y + 1)], /* TL */
365  v_grid[XY(x, y + 0)], /* BL */
366  NULL,
367  BM_CREATE_NOP);
368  }
369 
370  if (use_loop_interp && (larr_x_a[x][0] || larr_y_a[y][0])) {
371  /* bottom/left/top/right */
372  BMLoop *l_quad[4];
373  BMLoop *l_bound[4];
374  BMLoop *l_tmp;
375  uint x_side, y_side, i;
376  char interp_from;
377 
378  if (larr_x_a[x][0] && larr_y_a[y][0]) {
379  interp_from = 'B'; /* B == both */
380  l_tmp = larr_x_a[x][0];
381  }
382  else if (larr_x_a[x][0]) {
383  interp_from = 'X';
384  l_tmp = larr_x_a[x][0];
385  }
386  else {
387  interp_from = 'Y';
388  l_tmp = larr_y_a[y][0];
389  }
390 
391  BM_elem_attrs_copy(bm, bm, l_tmp->f, f);
392 
393  BM_face_as_array_loop_quad(f, l_quad);
394 
395  l_tmp = BM_FACE_FIRST_LOOP(f);
396 
397  if (use_flip) {
398  l_quad[0] = l_tmp;
399  l_tmp = l_tmp->next;
400  l_quad[1] = l_tmp;
401  l_tmp = l_tmp->next;
402  l_quad[3] = l_tmp;
403  l_tmp = l_tmp->next;
404  l_quad[2] = l_tmp;
405  }
406  else {
407  l_quad[2] = l_tmp;
408  l_tmp = l_tmp->next;
409  l_quad[3] = l_tmp;
410  l_tmp = l_tmp->next;
411  l_quad[1] = l_tmp;
412  l_tmp = l_tmp->next;
413  l_quad[0] = l_tmp;
414  }
415 
416  i = 0;
417 
418  for (x_side = 0; x_side < 2; x_side++) {
419  for (y_side = 0; y_side < 2; y_side++) {
420  if (interp_from == 'B') {
421  const float *w = weight_table[XY(x + x_side, y + y_side)];
422  l_bound[0] = larr_x_a[x][x_side]; /* B */
423  l_bound[1] = larr_y_a[y][y_side]; /* L */
424  l_bound[2] = larr_x_b[x][x_side]; /* T */
425  l_bound[3] = larr_y_b[y][y_side]; /* R */
426 
427  bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, w);
428  }
429  else if (interp_from == 'X') {
430  const float t = (float)(y + y_side) / (float)(ytot - 1);
431  l_bound[0] = larr_x_a[x][x_side]; /* B */
432  l_bound[1] = larr_x_b[x][x_side]; /* T */
433 
434  bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t);
435  }
436  else if (interp_from == 'Y') {
437  const float t = (float)(x + x_side) / (float)(xtot - 1);
438  l_bound[0] = larr_y_a[y][y_side]; /* L */
439  l_bound[1] = larr_y_b[y][y_side]; /* R */
440 
441  bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t);
442  }
443  else {
444  BLI_assert(0);
445  }
446  }
447  }
448  }
449  /* end interp */
450 
452  f->mat_nr = mat_nr;
453  if (use_smooth) {
455  }
456  }
457  }
458 
459  if (use_loop_interp) {
460  MEM_freeN(larr_x_a);
461  MEM_freeN(larr_y_a);
462  MEM_freeN(larr_x_b);
463  MEM_freeN(larr_y_b);
464  }
465 
466  if (weight_table) {
467  MEM_freeN(weight_table);
468  }
469 
470 #undef XY
471 }
472 
473 static void bm_grid_fill(BMesh *bm,
474  struct BMEdgeLoopStore *estore_a,
475  struct BMEdgeLoopStore *estore_b,
476  struct BMEdgeLoopStore *estore_rail_a,
477  struct BMEdgeLoopStore *estore_rail_b,
478  const short mat_nr,
479  const bool use_smooth,
480  const bool use_interp_simple)
481 {
482 #define USE_FLIP_DETECT
483 
484  const uint xtot = (uint)BM_edgeloop_length_get(estore_a);
485  const uint ytot = (uint)BM_edgeloop_length_get(estore_rail_a);
486  // BMVert *v;
487  uint i;
488 #ifdef DEBUG
489  uint x, y;
490 #endif
491  LinkData *el;
492  bool use_flip = false;
493 
494  ListBase *lb_a = BM_edgeloop_verts_get(estore_a);
495  ListBase *lb_b = BM_edgeloop_verts_get(estore_b);
496 
497  ListBase *lb_rail_a = BM_edgeloop_verts_get(estore_rail_a);
498  ListBase *lb_rail_b = BM_edgeloop_verts_get(estore_rail_b);
499 
500  BMVert **v_grid = MEM_callocN(sizeof(BMVert *) * (size_t)(xtot * ytot), __func__);
518  BLI_assert(((LinkData *)lb_a->first)->data == ((LinkData *)lb_rail_a->first)->data); /* BL */
519  BLI_assert(((LinkData *)lb_b->first)->data == ((LinkData *)lb_rail_a->last)->data); /* TL */
520  BLI_assert(((LinkData *)lb_b->last)->data == ((LinkData *)lb_rail_b->last)->data); /* TR */
521  BLI_assert(((LinkData *)lb_a->last)->data == ((LinkData *)lb_rail_b->first)->data); /* BR */
522 
523  for (el = lb_a->first, i = 0; el; el = el->next, i++) {
524  v_grid[i] = el->data;
525  }
526  for (el = lb_b->first, i = 0; el; el = el->next, i++) {
527  v_grid[(ytot * xtot) + (i - xtot)] = el->data;
528  }
529  for (el = lb_rail_a->first, i = 0; el; el = el->next, i++) {
530  v_grid[xtot * i] = el->data;
531  }
532  for (el = lb_rail_b->first, i = 0; el; el = el->next, i++) {
533  v_grid[(xtot * i) + (xtot - 1)] = el->data;
534  }
535 #ifdef DEBUG
536  for (x = 1; x < xtot - 1; x++) {
537  for (y = 1; y < ytot - 1; y++) {
538  BLI_assert(v_grid[(y * xtot) + x] == NULL);
539  }
540  }
541 #endif
542 
543 #ifdef USE_FLIP_DETECT
544  {
545  ListBase *lb_iter[4] = {lb_a, lb_b, lb_rail_a, lb_rail_b};
546  const int lb_iter_dir[4] = {-1, 1, 1, -1};
547  int winding_votes = 0;
548 
549  for (i = 0; i < 4; i++) {
550  LinkData *el_next;
551  for (el = lb_iter[i]->first; el && (el_next = el->next); el = el->next) {
552  BMEdge *e = BM_edge_exists(el->data, el_next->data);
553  if (BM_edge_is_boundary(e)) {
554  winding_votes += (e->l->v == el->data) ? lb_iter_dir[i] : -lb_iter_dir[i];
555  }
556  }
557  }
558  use_flip = (winding_votes < 0);
559  }
560 #endif
561 
562  bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip, use_interp_simple);
563  MEM_freeN(v_grid);
564 
565 #undef USE_FLIP_DETECT
566 }
567 
568 static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, bool set)
569 {
570  /* only handle closed loops in this case */
571  LinkData *link = BM_edgeloop_verts_get(estore)->first;
572  link = link->next;
573  while (link) {
574  BMEdge *e = BM_edge_exists(link->data, link->prev->data);
575  if (e) {
576  BM_elem_flag_set(e, hflag, set);
577  }
578  link = link->next;
579  }
580 }
581 
582 static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
583 {
584  return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK);
585 }
586 
587 static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v))
588 {
589  /* Normally operators don't check for hidden state
590  * but alternative would be to pass slot of rail edges. */
592  return false;
593  }
595 }
596 
598 {
599  ListBase eloops = {NULL, NULL};
600  ListBase eloops_rail = {NULL, NULL};
601  struct BMEdgeLoopStore *estore_a, *estore_b;
602  struct BMEdgeLoopStore *estore_rail_a, *estore_rail_b;
603  BMVert *v_a_first, *v_a_last;
604  BMVert *v_b_first, *v_b_last;
605  const short mat_nr = (short)BMO_slot_int_get(op->slots_in, "mat_nr");
606  const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth");
607  const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple");
608  GSet *split_edges = NULL;
609 
610  int count;
611  bool changed = false;
613 
614  count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, (void *)bm);
615 
616  if (count != 2) {
617  /* Note that this error message has been adjusted to make sense when called
618  * from the operator 'MESH_OT_fill_grid' which has a 'prepare' pass which can
619  * extract two 'rail' loops from a single edge loop, see T72075. */
621  op,
623  "Select two edge loops "
624  "or a single closed edge loop from which two edge loops can be calculated");
625  goto cleanup;
626  }
627 
628  estore_a = eloops.first;
629  estore_b = eloops.last;
630 
631  v_a_first = ((LinkData *)BM_edgeloop_verts_get(estore_a)->first)->data;
632  v_a_last = ((LinkData *)BM_edgeloop_verts_get(estore_a)->last)->data;
633  v_b_first = ((LinkData *)BM_edgeloop_verts_get(estore_b)->first)->data;
634  v_b_last = ((LinkData *)BM_edgeloop_verts_get(estore_b)->last)->data;
635 
636  if (BM_edgeloop_is_closed(estore_a) || BM_edgeloop_is_closed(estore_b)) {
637  BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Closed loops unsupported");
638  goto cleanup;
639  }
640 
641  /* ok. all error checking done, now we can find the rail edges */
642 
643  /* cheat here, temp hide all edges so they won't be included in rails
644  * this puts the mesh in an invalid state for a short time. */
645  bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, true);
646  bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, true);
647 
649  bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_first)) &&
651  bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_last))) {
652  estore_rail_a = eloops_rail.first;
653  estore_rail_b = eloops_rail.last;
654  }
655  else {
656  BM_mesh_edgeloops_free(&eloops_rail);
657 
659  bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_last)) &&
661  bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_first))) {
662  estore_rail_a = eloops_rail.first;
663  estore_rail_b = eloops_rail.last;
664  BM_edgeloop_flip(bm, estore_b);
665  }
666  else {
667  BM_mesh_edgeloops_free(&eloops_rail);
668  }
669  }
670 
671  bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, false);
672  bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, false);
673 
674  if (BLI_listbase_is_empty(&eloops_rail)) {
676  bm, op, BMERR_INVALID_SELECTION, "Loops are not connected by wire/boundary edges");
677  goto cleanup;
678  }
679 
680  BLI_assert(estore_a != estore_b);
681  BLI_assert(v_a_last != v_b_last);
682 
683  if (BM_edgeloop_overlap_check(estore_rail_a, estore_rail_b)) {
684  BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Connecting edge loops overlap");
685  goto cleanup;
686  }
687 
688  /* add vertices if needed */
689  {
690  struct BMEdgeLoopStore *estore_pairs[2][2] = {
691  {estore_a, estore_b},
692  {estore_rail_a, estore_rail_b},
693  };
694  int i;
695 
696  for (i = 0; i < 2; i++) {
697  const int len_a = BM_edgeloop_length_get(estore_pairs[i][0]);
698  const int len_b = BM_edgeloop_length_get(estore_pairs[i][1]);
699  if (len_a != len_b) {
700  if (split_edges == NULL) {
701  split_edges = BLI_gset_ptr_new(__func__);
702  }
703 
704  if (len_a < len_b) {
705  BM_edgeloop_expand(bm, estore_pairs[i][0], len_b, true, split_edges);
706  }
707  else {
708  BM_edgeloop_expand(bm, estore_pairs[i][1], len_a, true, split_edges);
709  }
710  }
711  }
712  }
713 
714  /* finally we have all edge loops needed */
715  bm_grid_fill(
716  bm, estore_a, estore_b, estore_rail_a, estore_rail_b, mat_nr, use_smooth, use_interp_simple);
717 
718  changed = true;
719 
720  if (split_edges) {
721  GSetIterator gs_iter;
722  GSET_ITER (gs_iter, split_edges) {
723  BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
724  BM_edge_collapse(bm, e, e->v2, true, true);
725  }
726  BLI_gset_free(split_edges, NULL);
727  }
728 
729 cleanup:
730  BM_mesh_edgeloops_free(&eloops);
731  BM_mesh_edgeloops_free(&eloops_rail);
732 
733  if (changed) {
735  }
736 }
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_interp(const struct CustomData *data)
Definition: customdata.c:3869
void CustomData_bmesh_interp(struct CustomData *data, const void **src_blocks, const float *weights, const float *sub_weights, int count, void *dst_block)
Definition: customdata.c:4048
#define BLI_assert(a)
Definition: BLI_assert.h:58
struct GSet GSet
Definition: BLI_ghash.h:189
GSet * BLI_gset_ptr_new(const char *info)
#define GSET_ITER(gs_iter_, gset_)
Definition: BLI_ghash.h:268
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:255
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void transform_point_by_tri_v3(float pt_tar[3], float const pt_src[3], const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
Definition: math_geom.c:4121
void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2], const float co[2], float w[4])
Definition: math_geom.c:4026
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_v3v3(const float a[3], const float b[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 void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNPACK4(a)
#define UNUSED(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
BMFace * BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag)
Make Quad/Triangle.
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition: bmesh_core.c:58
@ BM_CREATE_NOP
Definition: bmesh_core.h:27
void BM_edgeloop_expand(BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
void BM_mesh_edgeloops_free(ListBase *eloops)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data, BMVert *v_src, BMVert *v_dst)
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_overlap_check(struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b)
void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
@ BMERR_INVALID_SELECTION
Definition: bmesh_error.h:60
void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMVert * BM_edge_collapse(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces)
Definition: bmesh_mods.c:566
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_edge_flag_test_bool(bm, e, oflag)
#define BMO_face_flag_enable(bm, e, oflag)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
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)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define XY(_x, _y)
static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_bound[2], const float t)
static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, BMLoop *l, BMLoop *l_bound[4], const float w[4])
#define FACE_OUT
Definition: bmo_fill_grid.c:37
static void barycentric_weights_v2_grid_cache(const uint xtot, const uint ytot, float(*weight_table)[4])
static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const uint xtot, const uint ytot, const short mat_nr, const bool use_smooth, const bool use_flip, const bool use_interp_simple)
static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b, BMLoop *l_pair[2])
#define EDGE_MARK
Definition: bmo_fill_grid.c:36
static void quad_verts_to_barycentric_tri(float tri[3][3], const float co_a[3], const float co_b[3], const float co_a_next[3], const float co_b_next[3], const float co_a_prev[3], const float co_b_prev[3], const bool is_flip)
Definition: bmo_fill_grid.c:62
static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2])
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
void bmo_grid_fill_exec(BMesh *bm, BMOperator *op)
static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v))
static void bm_grid_fill(BMesh *bm, struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b, struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b, const short mat_nr, const bool use_smooth, const bool use_interp_simple)
static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, bool set)
static void quad_edges_to_normal(float no[3], const float co_a1[3], const float co_a2[3], const float co_b1[3], const float co_b2[3])
Definition: bmo_fill_grid.c:45
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
short mat_nr
Definition: bmesh_class.h:281
void * data
Definition: bmesh_class.h:63
BMHeader head
Definition: bmesh_class.h:157
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
BMHeader head
Definition: bmesh_class.h:97
CustomData vdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
void * data
Definition: DNA_listBase.h:42
struct LinkData * next
Definition: DNA_listBase.h:41
struct LinkData * prev
Definition: DNA_listBase.h:41
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47