Blender  V2.93
bmo_create.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 
27 #include "bmesh.h"
28 
29 #include "intern/bmesh_operators_private.h" /* own include */
30 
31 #define ELE_NEW 1
32 #define ELE_OUT 2
33 
34 /* This is what runs when pressing the F key
35  * doing the best thing here isn't always easy create vs dissolve, its nice to support
36  * but it _really_ gives issues we might have to not call dissolve. - campbell
37  */
39 {
40  BMOIter oiter;
41  BMHeader *h;
42  int totv = 0, tote = 0, totf = 0;
43  const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr");
44  const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth");
45 
46  /* count number of each element type we were passe */
47  BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) {
48  switch (h->htype) {
49  case BM_VERT:
51  totv++;
52  break;
53  case BM_EDGE:
55  tote++;
56  break;
57  case BM_FACE:
59  totf++;
60  break;
61  }
62  }
63 
64  /* --- Support Edge Creation ---
65  * simple case when we only have 2 verts selected.
66  */
67  if (totv == 2 && tote == 0 && totf == 0) {
68  BMVert *verts[2];
69  BMEdge *e;
70 
71  if (BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2) == 2) {
72  /* create edge */
75  tote += 1;
77  }
78  return;
79  }
80 
81  /* --- Support for Special Case ---
82  * where there is a contiguous edge ring with one isolated vertex.
83  *
84  * This example shows 2 edges created from 3 verts
85  * with 1 free standing vertex. Dotted lines denote the 2 edges that are created.
86  *
87  * note that this works for any sided shape.
88  *
89  * +--------+
90  * | .
91  * | .
92  * | .
93  * | .
94  * +........+ <-- starts out free standing.
95  *
96  */
97 
98  /* Here we check for consistency and create 2 edges */
99  if (totf == 0 && totv >= 4 && totv == tote + 2) {
100  /* find a free standing vertex and 2 endpoint verts */
101  BMVert *v, *v_free = NULL, *v_a = NULL, *v_b = NULL;
102  bool ok = true;
103 
104  BMO_ITER (v, &oiter, op->slots_in, "geom", BM_VERT) {
105  /* count how many flagged edges this vertex uses */
106  const int tot_edges = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, ELE_NEW, true);
107  if (tot_edges == 0) {
108  /* only accept 1 free vert */
109  if (v_free == NULL) {
110  v_free = v;
111  }
112  else {
113  ok = false;
114  } /* only ever want one of these */
115  }
116  else if (tot_edges == 1) {
117  if (v_a == NULL) {
118  v_a = v;
119  }
120  else if (v_b == NULL) {
121  v_b = v;
122  }
123  else {
124  ok = false;
125  } /* only ever want 2 of these */
126  }
127  else if (tot_edges == 2) {
128  /* do nothing, regular case */
129  }
130  else {
131  ok = false; /* if a vertex has 3+ edge users then cancel - this is only simple cases */
132  }
133 
134  if (ok == false) {
135  break;
136  }
137  }
138 
139  if (ok == true && v_free && v_a && v_b) {
140  BMEdge *e;
141 
142  e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE);
144 
145  e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE);
147  tote += 2;
148  }
149  }
150  /* --- end special case support, continue as normal --- */
151 
152  /* -------------------------------------------------------------------- */
153  /* EdgeNet Create */
154  if (tote != 0) {
155  /* call edgenet prepare op so additional face creation cases work */
156 
158  BMO_op_initf(bm, &op_sub, op->flag, "edgenet_prepare edges=%fe", ELE_NEW);
159  BMO_op_exec(bm, &op_sub);
160  BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "edges.out", BM_EDGE, ELE_NEW);
162 
164  &op_sub,
165  op->flag,
166  "edgenet_fill edges=%fe mat_nr=%i use_smooth=%b sides=%i",
167  ELE_NEW,
168  mat_nr,
169  use_smooth,
170  10000);
171 
172  BMO_op_exec(bm, &op_sub);
173 
174  /* return if edge net create did something */
175  if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) {
176  BMO_slot_copy(&op_sub, slots_out, "faces.out", op, slots_out, "faces.out");
178  return;
179  }
180 
182  }
183 
184  /* -------------------------------------------------------------------- */
185  /* Dissolve Face */
186  if (totf != 0) { /* should be (totf > 1)... see below */
187  /* note: allow this to run on single faces so running on a single face
188  * won't go on to create a face, treating them as random */
190  BMO_op_initf(bm, &op_sub, op->flag, "dissolve_faces faces=%ff", ELE_NEW);
191  BMO_op_exec(bm, &op_sub);
192 
193  /* if we dissolved anything, then return */
194  if (BMO_slot_buffer_count(op_sub.slots_out, "region.out")) {
195  BMO_slot_copy(&op_sub, slots_out, "region.out", op, slots_out, "faces.out");
197  return;
198  }
199 
201  }
202 
203  /* -------------------------------------------------------------------- */
204  /* Fill EdgeLoop's - fills isolated loops, different from edgenet */
205  if (tote > 2) {
207  /* note: in most cases 'edgenet_fill' will handle this case since in common cases
208  * users fill in empty spaces, however its possible to have an edge selection around
209  * existing geometry that makes 'edgenet_fill' fail. */
210  BMO_op_initf(bm, &op_sub, op->flag, "edgeloop_fill edges=%fe", ELE_NEW);
211  BMO_op_exec(bm, &op_sub);
212 
213  /* return if edge loop fill did something */
214  if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) {
215  BMO_slot_copy(&op_sub, slots_out, "faces.out", op, slots_out, "faces.out");
217  return;
218  }
219 
221  }
222 
223  /* -------------------------------------------------------------------- */
224  /* Continue with ad-hoc fill methods since operators fail,
225  * edge, vcloud... may add more */
226 
227  if (0) { /* nice feature but perhaps it should be a different tool? */
228 
229  /* tricky feature for making a line/edge from selection history...
230  *
231  * Rather than do nothing, when 5+ verts are selected, check if they are in our history,
232  * when this is so, we can make edges from them, but _not_ a face,
233  * if it is the intention to make a face the user can just hit F again
234  * since there will be edges next time around.
235  *
236  * if all history verts have ELE_NEW flagged and the total number of history verts == totv,
237  * then we know the history contains all verts here and we can continue...
238  */
239 
240  BMEditSelection *ese;
241  int tot_ese_v = 0;
242 
243  for (ese = bm->selected.first; ese; ese = ese->next) {
244  if (ese->htype == BM_VERT) {
245  if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) {
246  tot_ese_v++;
247  }
248  else {
249  /* unflagged vert means we are not in sync */
250  tot_ese_v = -1;
251  break;
252  }
253  }
254  }
255 
256  if (tot_ese_v == totv) {
257  BMVert *v_prev = NULL;
258  /* yes, all select-history verts are accounted for, now make edges */
259 
260  for (ese = bm->selected.first; ese; ese = ese->next) {
261  if (ese->htype == BM_VERT) {
262  BMVert *v = (BMVert *)ese->ele;
263  if (v_prev) {
266  }
267  v_prev = v;
268  }
269  }
270  }
272  /* done creating edges */
273 
274  return;
275  }
276 
277  /* -------------------------------------------------------------------- */
278  /* Fill Vertex Cloud
279  *
280  * last resort when all else fails.
281  */
282  if (totv > 2) {
283  /* TODO, some of these vertices may be connected by edges,
284  * this connectivity could be used rather than treating
285  * them as a bunch of isolated verts. */
286 
287  BMVert **vert_arr = MEM_mallocN(sizeof(BMVert *) * totv, __func__);
288  BMFace *f;
289 
290  totv = BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
291 
292  BM_verts_sort_radial_plane(vert_arr, totv);
293 
294  /* create edges and find the winding (if faces are attached to any existing edges) */
295  f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true);
296 
297  if (f) {
299  f->mat_nr = mat_nr;
300  if (use_smooth) {
302  }
305  }
306 
307  MEM_freeN(vert_arr);
308  }
309 }
Read Guarded memory(de)allocation.
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
BMFace * BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool calc_winding, const bool create_edges)
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
copies face loop data from shared adjacent faces.
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:147
@ BM_CREATE_NO_DOUBLE
Definition: bmesh_core.h:29
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value)
Elem Iter Tool Flag Count.
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, void **array, const int len)
Operator Iterator as Array.
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
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_enable(bm, e, oflag)
#define BMO_vert_flag_enable(bm, e, oflag)
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt,...)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_slot_copy(op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_test(bm, e, oflag)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
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)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define ELE_NEW
Definition: bmo_create.c:31
#define ELE_OUT
Definition: bmo_create.c:32
void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
Definition: bmo_create.c:38
static double op_sub(double a, double b)
static float verts[][3]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
struct BMEditSelection * next
Definition: bmesh_marking.h:24
short mat_nr
Definition: bmesh_class.h:281
char htype
Definition: bmesh_class.h:76
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
ListBase selected
Definition: bmesh_class.h:356
void * first
Definition: DNA_listBase.h:47