1 #include "MEM_guardedalloc.h"
3 #include "DNA_meshdata_types.h"
4 #include "DNA_mesh_types.h"
5 #include "DNA_object_types.h"
6 #include "DNA_scene_types.h"
8 #include "BLI_utildefines.h"
11 #include "BLI_ghash.h"
12 #include "BLI_blenlib.h"
13 #include "BLI_array.h"
14 #include "BLI_utildefines.h"
17 #include "mesh_intern.h"
18 #include "bmesh_private.h"
24 #define BL(ptr) ((BMLoop*)(ptr))
26 static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op)
33 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
34 v2 = BMO_Get_MapPointer(bm, op, "targetmap", l->v);
35 /*ok: if v2 is NULL (e.g. not in the map) then it's
36 a target vert, otherwise it's a double*/
37 if (v2 && BM_Vert_In_Face(f, v2) && v2 != BL(l->prev)->v
38 && v2 != BL(l->next)->v)
46 if (split && doub != v2) {
48 BMFace *f2 = BM_Split_Face(bm, f, doub, v2, &nl, NULL);
50 remdoubles_splitface(f, bm, op);
51 remdoubles_splitface(f2, bm, op);
60 int remdoubles_face_overlaps(BMesh *bm, BMVert **varr,
61 int len, BMFace *exclude,
68 if (overlapface) *overlapface = NULL;
70 for(i=0; i < len; i++){
71 f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
73 amount = BM_Verts_In_Face(bm, f, varr, len);
75 if (overlapface) *overlapface = f;
78 f = BMIter_Step(&vertfaces);
85 void bmesh_weldverts_exec(BMesh *bm, BMOperator *op)
89 BMEdge *e, *e2, **edges = NULL;
90 BLI_array_declare(edges);
91 BMLoop *l, *l2, **loops = NULL;
92 BLI_array_declare(loops);
96 BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
97 if (BMO_Get_MapPointer(bm, op, "targetmap", v))
98 BMO_SetFlag(bm, v, ELE_DEL);
101 BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
102 remdoubles_splitface(f, bm, op);
105 BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
106 if (BMO_TestFlag(bm, e->v1, ELE_DEL) || BMO_TestFlag(bm, e->v2, ELE_DEL)) {
107 v = BMO_Get_MapPointer(bm, op, "targetmap", e->v1);
108 v2 = BMO_Get_MapPointer(bm, op, "targetmap", e->v2);
114 BMO_SetFlag(bm, e, EDGE_COL);
115 else if (!BM_Edge_Exist(v, v2))
116 BM_Make_Edge(bm, v, v2, e, 1);
118 BMO_SetFlag(bm, e, ELE_DEL);
122 BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
124 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
125 if (BMO_TestFlag(bm, l->v, ELE_DEL))
126 BMO_SetFlag(bm, f, FACE_MARK|ELE_DEL);
127 if (BMO_TestFlag(bm, l->e, EDGE_COL))
128 BM_SetIndex(f, BM_GetIndex(f)+1);
132 BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
133 if (!BMO_TestFlag(bm, f, FACE_MARK))
136 if (f->len - BM_GetIndex(f) < 3) {
137 BMO_SetFlag(bm, f, ELE_DEL);
141 BLI_array_empty(edges);
142 BLI_array_empty(loops);
144 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
147 if (BMO_TestFlag(bm, v, ELE_DEL))
148 v = BMO_Get_MapPointer(bm, op, "targetmap", v);
149 if (BMO_TestFlag(bm, v2, ELE_DEL))
150 v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2);
152 e2 = v != v2 ? BM_Edge_Exist(v, v2) : NULL;
154 for (b=0; b<a; b++) {
161 BLI_array_growone(edges);
162 BLI_array_growone(loops);
171 if (BLI_array_count(loops) < 3)
177 if (BMO_TestFlag(bm, v, ELE_DEL))
178 v = BMO_Get_MapPointer(bm, op, "targetmap", v);
179 if (BMO_TestFlag(bm, v2, ELE_DEL))
180 v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2);
182 f2 = BM_Make_Ngon(bm, v2, v, edges, a, 0);
184 BM_Copy_Attributes(bm, bm, f, f2);
187 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f2) {
189 BM_Copy_Attributes(bm, bm, l2, l);
196 BMO_CallOpf(bm, "del geom=%fvef context=%i", ELE_DEL, DEL_ONLYTAGGED);
198 BLI_array_free(edges);
199 BLI_array_free(loops);
202 static int vergaverco(const void *e1, const void *e2)
204 const BMVert *v1 = *(void**)e1, *v2 = *(void**)e2;
205 float x1 = v1->co[0] + v1->co[1] + v1->co[2];
206 float x2 = v2->co[0] + v2->co[1] + v2->co[2];
208 if (x1 > x2) return 1;
209 else if (x1 < x2) return -1;
213 #define VERT_TESTED 1
214 #define VERT_DOUBLE 2
215 #define VERT_TARGET 4
222 void bmesh_pointmerge_facedata_exec(BMesh *bm, BMOperator *op)
227 BMLoop *l, *firstl = NULL;
231 snapv = BMO_IterNew(&siter, bm, op, "snapv", BM_VERT);
232 tot = BM_Vert_FaceCount(snapv);
238 BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, snapv) {
243 for (i=0; i<bm->ldata.totlayer; i++) {
244 if (CustomData_layer_has_math(&bm->ldata, i)) {
245 int type = bm->ldata.layers[i].type;
248 e1 = CustomData_bmesh_get_layer_n(&bm->ldata, firstl->head.data, i);
249 e2 = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
251 CustomData_data_multiply(type, e2, fac);
254 CustomData_data_add(type, e1, e2);
259 BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
260 BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, v) {
264 CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, firstl->head.data, &l->head.data);
269 void bmesh_vert_average_facedata_exec(BMesh *bm, BMOperator *op)
274 BMLoop *l /* , *firstl = NULL */;
275 CDBlockBytes min, max;
279 for (i=0; i<bm->ldata.totlayer; i++) {
280 if (!CustomData_layer_has_math(&bm->ldata, i))
283 type = bm->ldata.layers[i].type;
284 CustomData_data_initminmax(type, &min, &max);
286 BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
287 BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, v) {
288 block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
289 CustomData_data_dominmax(type, block, &min, &max);
293 CustomData_data_multiply(type, &min, 0.5f);
294 CustomData_data_multiply(type, &max, 0.5f);
295 CustomData_data_add(type, &min, &max);
297 BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
298 BM_ITER(l, &iter, bm, BM_LOOPS_OF_VERT, v) {
299 block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i);
300 CustomData_data_copy_value(type, &min, block);
306 void bmesh_pointmerge_exec(BMesh *bm, BMOperator *op)
310 BMVert *v, *snapv = NULL;
313 BMO_Get_Vec(op, "mergeco", vec);
315 //BMO_CallOpf(bm, "collapse_uvs edges=%s", op, "edges");
316 BMO_Init_Op(&weldop, "weldverts");
318 BMO_ITER(v, &siter, bm, op, "verts", BM_VERT) {
321 copy_v3_v3(snapv->co, vec);
323 BMO_Insert_MapPointer(bm, &weldop, "targetmap", v, snapv);
327 BMO_Exec_Op(bm, &weldop);
328 BMO_Finish_Op(bm, &weldop);
331 void bmesh_collapse_exec(BMesh *bm, BMOperator *op)
336 BMEdge *e, **edges = NULL;
337 BLI_array_declare(edges);
338 float min[3], max[3];
341 BMO_CallOpf(bm, "collapse_uvs edges=%s", op, "edges");
342 BMO_Init_Op(&weldop, "weldverts");
344 BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE);
345 BMW_Init(&walker, bm, BMW_SHELL, EDGE_MARK, 0);
347 BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
348 if (!BMO_TestFlag(bm, e, EDGE_MARK))
351 e = BMW_Begin(&walker, e->v1);
352 BLI_array_empty(edges);
354 INIT_MINMAX(min, max);
355 for (tot=0; e; tot++, e=BMW_Step(&walker)) {
356 BLI_array_growone(edges);
359 DO_MINMAX(e->v1->co, min, max);
360 DO_MINMAX(e->v2->co, min, max);
363 add_v3_v3v3(min, min, max);
364 mul_v3_fl(min, 0.5f);
366 /*snap edges to a point. for initial testing purposes anyway.*/
367 for (i=0; i<tot; i++) {
368 VECCOPY(edges[i]->v1->co, min);
369 VECCOPY(edges[i]->v2->co, min);
371 if (edges[i]->v1 != edges[0]->v1)
372 BMO_Insert_MapPointer(bm, &weldop, "targetmap", edges[i]->v1, edges[0]->v1);
373 if (edges[i]->v2 != edges[0]->v1)
374 BMO_Insert_MapPointer(bm, &weldop, "targetmap", edges[i]->v2, edges[0]->v1);
378 BMO_Exec_Op(bm, &weldop);
379 BMO_Finish_Op(bm, &weldop);
382 BLI_array_free(edges);
385 /*uv collapse function*/
386 static void bmesh_collapsecon_do_layer(BMesh *bm, BMOperator *op, int layer)
392 void **blocks = NULL;
393 BLI_array_declare(blocks);
394 CDBlockBytes min, max;
395 int i, tot, type = bm->ldata.layers[layer].type;
397 BMO_Clear_Flag_All(bm, op, BM_ALL, 65535);
399 BMO_Flag_Buffer(bm, op, "edges", EDGE_MARK, BM_EDGE);
400 BMW_Init(&walker, bm, BMW_LOOPDATA_ISLAND, EDGE_MARK, layer);
402 BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
403 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
404 if (BMO_TestFlag(bm, l->e, EDGE_MARK)) {
406 BLI_array_empty(blocks);
408 l2 = BMW_Begin(&walker, l);
410 CustomData_data_initminmax(type, &min, &max);
411 for (tot=0; l2; tot++, l2=BMW_Step(&walker)) {
412 BLI_array_growone(blocks);
413 blocks[tot] = CustomData_bmesh_get_layer_n(&bm->ldata, l2->head.data, layer);
414 CustomData_data_dominmax(type, blocks[tot], &min, &max);
418 CustomData_data_multiply(type, &min, 0.5f);
419 CustomData_data_multiply(type, &max, 0.5f);
420 CustomData_data_add(type, &min, &max);
422 /*snap CD (uv, vcol) points to their centroid*/
423 for (i=0; i<tot; i++) {
424 CustomData_data_copy_value(type, &min, blocks[i]);
432 BLI_array_free(blocks);
435 void bmesh_collapsecon_exec(BMesh *bm, BMOperator *op)
439 for (i=0; i<bm->ldata.totlayer; i++) {
440 if (CustomData_layer_has_math(&bm->ldata, i))
441 bmesh_collapsecon_do_layer(bm, op, i);
445 void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op)
451 BLI_array_declare(verts);
455 dist = BMO_Get_Float(op, "dist");
458 BMO_Init_Op(&weldop, "weldverts");
461 BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
462 BLI_array_growone(verts);
466 /*sort by vertex coordinates added together*/
467 qsort(verts, BLI_array_count(verts), sizeof(void*), vergaverco);
469 len = BLI_array_count(verts);
470 for (i=0; i<len; i++) {
472 if (BMO_TestFlag(bm, v, VERT_TESTED)) continue;
474 BMO_SetFlag(bm, v, VERT_TESTED);
475 for (j=i+1; j<len; j++) {
479 //if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
481 if ((v2->co[0]-v->co[0]) + (v2->co[1]-v->co[1]) + (v2->co[2]-v->co[2]) > distsqr*4.0f)
484 vec[0] = v->co[0] - v2->co[0];
485 vec[1] = v->co[1] - v2->co[1];
486 vec[2] = v->co[2] - v2->co[2];
488 if (INPR(vec, vec) < distsqr) {
489 BMO_SetFlag(bm, v2, VERT_TESTED);
490 BMO_SetFlag(bm, v2, VERT_DOUBLE);
491 BMO_SetFlag(bm, v, VERT_TARGET);
493 BMO_Insert_MapPointer(bm, &weldop, "targetmap", v2, v);
498 BLI_array_free(verts);
500 BMO_Exec_Op(bm, &weldop);
501 BMO_Finish_Op(bm, &weldop);
505 void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op)
510 BLI_array_declare(verts);
512 int i, j, len, keepvert;
514 dist = BMO_Get_Float(op, "dist");
518 BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
519 BLI_array_growone(verts);
523 keepvert = BMO_IterNew(&oiter, bm, op, "keepverts", BM_VERT) != NULL;
525 /*sort by vertex coordinates added together*/
526 qsort(verts, BLI_array_count(verts), sizeof(void*), vergaverco);
528 BMO_Flag_Buffer(bm, op, "keepverts", VERT_KEEP, BM_VERT);
530 len = BLI_array_count(verts);
531 for (i=0; i<len; i++) {
533 if (BMO_TestFlag(bm, v, VERT_DOUBLE)) continue;
535 for (j=i+1; j<len; j++) {
537 if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
541 if (BMO_TestFlag(bm, v2, VERT_KEEP) == BMO_TestFlag(bm, v, VERT_KEEP))
545 if (compare_len_v3v3(v->co, v2->co, dist)) {
546 BMO_SetFlag(bm, v2, VERT_DOUBLE);
547 BMO_SetFlag(bm, v, VERT_TARGET);
549 BMO_Insert_MapPointer(bm, op, "targetmapout", v2, v);
554 BLI_array_free(verts);
557 void bmesh_automerge_exec(BMesh *bm, BMOperator *op)
563 BLI_array_declare(verts);
565 int i, j, len /* , keepvert */;
567 dist = BMO_Get_Float(op, "dist");
571 BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
572 BLI_array_growone(verts);
576 BMO_Init_Op(&weldop, "weldverts");
578 /*sort by vertex coordinates added together*/
579 qsort(verts, BLI_array_count(verts), sizeof(void*), vergaverco);
581 BMO_Flag_Buffer(bm, op, "verts", VERT_KEEP, BM_VERT);
583 len = BLI_array_count(verts);
584 for (i=0; i<len; i++) {
586 if (BMO_TestFlag(bm, v, VERT_DOUBLE)) continue;
588 for (j=i+1; j<len; j++) {
590 if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
593 /* only allow unselected -> selected */
594 if (BMO_TestFlag(bm, v2, VERT_IN))
597 if (compare_len_v3v3(v->co, v2->co, dist)) {
598 BMO_SetFlag(bm, v2, VERT_DOUBLE);
599 BMO_SetFlag(bm, v, VERT_TARGET);
601 BMO_Insert_MapPointer(bm, &weldop, "targetmap", v2, v);
606 BMO_Exec_Op(bm, &weldop);
607 BMO_Finish_Op(bm, &weldop);
609 BLI_array_free(verts);