2
* ***** BEGIN GPL LICENSE BLOCK *****
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software Foundation,
16
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
* Contributor(s): Nicholas Bishop
20
* ***** END GPL LICENSE BLOCK *****
23
#include "MEM_guardedalloc.h"
25
#include "BLI_array.h"
27
#include "BLI_utildefines.h"
30
#include "intern/bmesh_operators_private.h"
33
SYMM_OUTPUT_GEOM = (1 << 0)
36
/* Note: don't think there's much need to make these user-adjustable? */
37
#define SYMM_AXIS_THRESHOLD 0.00002f
38
#define SYMM_VERT_THRESHOLD 0.00002f
41
/* Coordinate lies on the side being copied from */
43
/* Coordinate lies on the side being copied from and within the
46
/* Coordinate lies on the side being copied to */
55
BMO_SymmDirection direction;
57
/* Maps from input vertices to their mirrors. If the vertex
58
* doesn't have a mirror, it's not in this map. If the vertex is
59
* within the axis threshold, it's mapped to itself. */
62
/* Edges that cross the symmetry plane and are asymmetric get
63
* split. This map goes from input edges to output vertices. If an
64
* edge is not split, it's not in this map. */
65
GHash *edge_split_map;
68
/* Return which side the coordinate lies on */
69
static SymmSide symm_co_side(const Symm *symm,
72
float comp = co[symm->axis];
73
if (ELEM3(symm->direction,
74
BMO_SYMMETRIZE_NEGATIVE_X,
75
BMO_SYMMETRIZE_NEGATIVE_Y,
76
BMO_SYMMETRIZE_NEGATIVE_Z))
82
if (comp < SYMM_AXIS_THRESHOLD)
83
return SYMM_SIDE_AXIS;
85
return SYMM_SIDE_KEEP;
88
return SYMM_SIDE_KILL;
91
/* Output vertices and the vert_map array */
92
static void symm_verts_mirror(Symm *symm)
95
BMVert *src_v, *dst_v;
97
symm->vert_symm_map = BLI_ghash_ptr_new(AT);
99
BMO_ITER (src_v, &oiter, symm->op->slots_in, "input", BM_VERT) {
100
SymmSide side = symm_co_side(symm, src_v->co);
105
/* The vertex is outside the axis area; output its mirror */
106
copy_v3_v3(co, src_v->co);
107
co[symm->axis] = -co[symm->axis];
109
dst_v = BM_vert_create(symm->bm, co, src_v, 0);
110
BMO_elem_flag_enable(symm->bm, dst_v, SYMM_OUTPUT_GEOM);
111
BLI_ghash_insert(symm->vert_symm_map, src_v, dst_v);
115
/* The vertex is within the axis area, snap to center */
116
src_v->co[symm->axis] = 0;
117
/* Vertex isn't copied, map to itself */
118
BLI_ghash_insert(symm->vert_symm_map, src_v, src_v);
122
/* The vertex does not lie in the half-space being
123
* copied from, nothing to do */
129
static int symm_edge_crosses_axis(const Symm *symm, const BMEdge *e)
131
const int sides[2] = {symm_co_side(symm, e->v1->co),
132
symm_co_side(symm, e->v2->co)};
134
return ((sides[0] != SYMM_SIDE_AXIS) &&
135
(sides[1] != SYMM_SIDE_AXIS) &&
136
(sides[0] != sides[1]));
139
/* Output edge split vertices for asymmetric edges and the edge_splits
141
static void symm_split_asymmetric_edges(Symm *symm)
146
symm->edge_split_map = BLI_ghash_ptr_new(AT);
148
BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) {
151
copy_v3_v3(flipped, e->v1->co);
152
flipped[symm->axis] = -flipped[symm->axis];
154
if (symm_edge_crosses_axis(symm, e) &&
155
(!compare_v3v3(e->v2->co, flipped, SYMM_VERT_THRESHOLD)))
157
/* Endpoints lie on opposite sides and are asymmetric */
160
float lambda = 0, edge_dir[3], co[3];
161
float plane_co[3][3][3] = {
163
{{0, 0, 0}, {0, 1, 0}, {0, 0, 1}},
165
{{0, 0, 0}, {1, 0, 0}, {0, 0, 1}},
167
{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}},
171
/* Find intersection of edge with symmetry plane */
172
sub_v3_v3v3(edge_dir, e->v2->co, e->v1->co);
173
normalize_v3(edge_dir);
174
r = isect_ray_plane_v3(e->v1->co,
176
plane_co[symm->axis][0],
177
plane_co[symm->axis][1],
178
plane_co[symm->axis][2],
182
madd_v3_v3v3fl(co, e->v1->co, edge_dir, lambda);
185
/* Edge is asymmetric, split it with a new vertex */
186
v = BM_vert_create(symm->bm, co, e->v1, 0);
187
BMO_elem_flag_enable(symm->bm, v, SYMM_OUTPUT_GEOM);
188
BLI_ghash_insert(symm->edge_split_map, e, v);
193
static void symm_mirror_edges(Symm *symm)
198
BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) {
199
BMVert *v1 = NULL, *v2 = NULL;
202
v1 = BLI_ghash_lookup(symm->vert_symm_map, e->v1);
203
v2 = BLI_ghash_lookup(symm->vert_symm_map, e->v2);
206
e_new = BM_edge_create(symm->bm, v1, v2, e, BM_CREATE_NO_DOUBLE);
207
BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM);
210
if (BLI_ghash_haskey(symm->edge_split_map, e)) {
211
BMVert *v_split = BLI_ghash_lookup(symm->edge_split_map, e);
213
/* Output the keep side of the split edge */
215
e_new = BM_edge_create(symm->bm, v_split, e->v2, e, BM_CREATE_NO_DOUBLE);
216
BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM);
220
e_new = BM_edge_create(symm->bm, e->v1, v_split, e, BM_CREATE_NO_DOUBLE);
221
BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM);
225
/* Output the kill side of the split edge */
226
e_new = BM_edge_create(symm->bm, v1, v2, e, BM_CREATE_NO_DOUBLE);
227
BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM);
233
/****************************** SymmPoly ******************************/
236
/* Indices into the source mvert array (or -1 if not in that array) */
238
/* Indices into the destination mvert array, these are vertices
239
* created by an edge split (-1 for vertices not created by edge
243
/* Number of vertices in the polygon */
246
/* True only if none of the polygon's edges were split */
247
bool already_symmetric;
252
static void symm_poly_with_splits(const Symm *symm,
262
/* Count vertices and check for edge splits */
264
out->already_symmetric = true;
265
BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
266
if (BLI_ghash_haskey(symm->edge_split_map, l->e)) {
268
out->already_symmetric = false;
273
BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
274
BMVert *split = BLI_ghash_lookup(symm->edge_split_map, l->e);
276
out->src_verts[i] = l->v;
277
out->edge_verts[i] = NULL;
281
out->src_verts[i] = NULL;
282
out->edge_verts[i] = split;
288
static const float *symm_poly_co(const SymmPoly *sp, int v)
290
if (sp->src_verts[v])
291
return sp->src_verts[v]->co;
292
else if (sp->edge_verts[v])
293
return sp->edge_verts[v]->co;
298
static SymmSide symm_poly_co_side(const Symm *symm,
302
return symm_co_side(symm, symm_poly_co(sp, v));
305
/* Return the index of the vertex in the destination array at corner
306
* 'v' of the polygon, or -1 if not in that array */
307
static BMVert *symm_poly_dst(const SymmPoly *sp, int v)
309
if (sp->edge_verts[v])
310
return sp->edge_verts[v];
311
else if (sp->src_verts[v])
312
return sp->src_verts[v];
317
/* Same as above, but returns the index of the mirror if available, or
318
* the same index if on the axis, or -1 otherwise */
319
static BMVert *symm_poly_mirror_dst(const Symm *symm,
323
if (sp->edge_verts[v])
324
return sp->edge_verts[v];
325
else if (sp->src_verts[v]) {
326
if (BLI_ghash_haskey(symm->vert_symm_map, sp->src_verts[v]))
327
return BLI_ghash_lookup(symm->vert_symm_map, sp->src_verts[v]);
329
return sp->src_verts[v];
335
static bool symm_poly_next_crossing(const Symm *symm,
343
for (i = 0; i < sp->len; i++) {
344
(*l1) = (start + i) % sp->len;
345
(*l2) = ((*l1) + 1) % sp->len;
347
if ((symm_poly_co_side(symm, sp, *l1) == SYMM_SIDE_KILL) ^
348
(symm_poly_co_side(symm, sp, *l2) == SYMM_SIDE_KILL))
354
BLI_assert(!"symm_poly_next_crossing failed");
358
static BMFace *symm_face_create_v(BMesh *bm, BMFace *example,
359
BMVert **fv, BMEdge **fe, int len)
364
/* TODO: calling symmetrize in dynamic-topology sculpt mode
365
* frequently tries to create faces of length less than two,
366
* should investigate further */
370
for (i = 0; i < len; i++) {
371
int j = (i + 1) % len;
372
fe[i] = BM_edge_exists(fv[i], fv[j]);
374
fe[i] = BM_edge_create(bm, fv[i], fv[j], NULL, 0);
375
BMO_elem_flag_enable(bm, fe[i], SYMM_OUTPUT_GEOM);
378
f_new = BM_face_create(bm, fv, fe, len, BM_CREATE_NO_DOUBLE);
380
BM_elem_attrs_copy(bm, bm, example, f_new);
381
BM_face_select_set(bm, f_new, true);
382
BMO_elem_flag_enable(bm, f_new, SYMM_OUTPUT_GEOM);
387
static void symm_mesh_output_poly_zero_splits(Symm *symm,
398
/* Output the keep side of the input polygon */
399
for (i = 0; i < segment_len; i++) {
400
const int offset = (start + i) % sp->len;
401
BLI_assert(sp->src_verts[offset]);
402
fv[j++] = sp->src_verts[offset];
405
/* Output the kill side of the polygon */
406
for (i = segment_len - 1; i >= 0; i--) {
407
const int offset = (start + i) % sp->len;
409
if (symm_poly_co_side(symm, sp, offset) == SYMM_SIDE_KEEP) {
410
BLI_assert(sp->src_verts[offset]);
411
fv[j++] = BLI_ghash_lookup(symm->vert_symm_map,
412
sp->src_verts[offset]);
416
symm_face_create_v(symm->bm, sp->src_face, fv, fe, j);
419
static void symm_mesh_output_poly_with_splits(Symm *symm,
428
/* Output the keep side of the input polygon */
430
for (i = 0; i < segment_len; i++) {
431
const int offset = (start + i) % sp->len;
432
BMVert *v = symm_poly_dst(sp, offset);
439
symm_face_create_v(symm->bm, sp->src_face, fv, fe, segment_len);
441
/* Output the kill side of the input polygon */
443
for (i = 0; i < segment_len; i++) {
444
const int offset = (start + i) % sp->len;
445
BMVert *v = symm_poly_mirror_dst(symm, sp, offset);
447
fv[segment_len - i - 1] = v;
451
symm_face_create_v(symm->bm, sp->src_face, fv, fe, segment_len);
454
static void symm_mirror_polygons(Symm *symm)
461
BLI_array_declare(pv);
462
BLI_array_declare(fv);
463
BLI_array_declare(fe);
465
BMO_ITER (f, &oiter, symm->op->slots_in, "input", BM_FACE) {
468
bool mirror_all = true, ignore_all = true;
470
/* Check if entire polygon can be mirrored or ignored */
471
BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
472
const SymmSide side = symm_co_side(symm, l->v->co);
473
if (side == SYMM_SIDE_KILL)
475
else if (side == SYMM_SIDE_KEEP)
482
/* Make a mirrored copy of the polygon */
486
BLI_array_grow_items(fv, f->len);
487
BLI_array_grow_items(fe, f->len);
490
BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
493
if (symm_co_side(symm, l->v->co) == SYMM_SIDE_KEEP)
494
fv[i] = BLI_ghash_lookup(symm->vert_symm_map, l->v);
499
symm_face_create_v(symm->bm, f, fv, fe, f->len);
501
else if (ignore_all) {
502
BM_face_kill(symm->bm, f);
507
int double_l2, double_l3;
511
BLI_array_grow_items(pv, f->len * 4);
513
sp.edge_verts = pv + f->len * 2;
514
symm_poly_with_splits(symm, f, &sp);
516
/* Find first loop edge crossing the axis */
517
symm_poly_next_crossing(symm, &sp, 0, &l1, &l2);
519
/* If crossing isn't kill to keep, find the next one */
520
if (symm_poly_co_side(symm, &sp, l1) != SYMM_SIDE_KILL) {
521
symm_poly_next_crossing(symm, &sp, l2, &l1, &l2);
524
/* Find next crossing (keep to kill) */
525
symm_poly_next_crossing(symm, &sp, l2, &l3, &l4);
530
segment_len = l3 - l2 + 1;
532
segment_len = (sp.len - l2 + 1) + l3;
534
double_l2 = symm_poly_co_side(symm, &sp, l2) == SYMM_SIDE_KEEP;
535
double_l3 = symm_poly_co_side(symm, &sp, l3) == SYMM_SIDE_KEEP;
537
/* Calculate number of new polygons/loops */
538
if (segment_len == 0) {
540
else if (sp.already_symmetric) {
543
if (double_l2 && double_l3)
544
new_loops = segment_len * 2;
545
else if (!double_l2 && !double_l3)
546
new_loops = segment_len * 2 - 2;
548
new_loops = segment_len * 2 - 1;
552
BLI_array_grow_items(fv, new_loops);
553
BLI_array_grow_items(fe, new_loops);
555
symm_mesh_output_poly_zero_splits(symm, &sp,
558
BM_face_kill(symm->bm, f);
560
else if (!double_l2 && !double_l3) {
563
BLI_array_grow_items(fv, segment_len);
564
BLI_array_grow_items(fe, segment_len);
566
symm_mesh_output_poly_with_splits(symm, &sp,
571
BM_face_kill(symm->bm, f);
576
BLI_array_grow_items(fv, segment_len);
577
BLI_array_grow_items(fe, segment_len);
579
symm_mesh_output_poly_with_splits(symm, &sp,
584
BM_face_kill(symm->bm, f);
586
/* Output bridge triangle */
590
BLI_array_grow_items(fv, 3);
591
BLI_array_grow_items(fe, 3);
594
fv[0] = symm_poly_dst(&sp, l2);
595
fv[1] = symm_poly_mirror_dst(symm, &sp, l2);
596
fv[2] = symm_poly_dst(&sp, l3);
598
else if (double_l3) {
599
fv[0] = symm_poly_dst(&sp, l3);
600
fv[1] = symm_poly_mirror_dst(symm, &sp, l3);
601
fv[2] = symm_poly_dst(&sp, l2);
604
BLI_assert(fv[0] && fv[1] && fv[2]);
606
symm_face_create_v(symm->bm, NULL, fv, fe, 3);
616
/* Remove unused edges and vertices from the side being copied to */
617
static void symm_kill_unused(Symm *symm)
623
/* Kill unused edges */
624
BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) {
625
const int crosses = symm_edge_crosses_axis(symm, e);
626
const int symmetric = (crosses &&
627
(!BLI_ghash_haskey(symm->edge_split_map, e)));
629
if (((symm_co_side(symm, e->v1->co) == SYMM_SIDE_KILL) ||
630
(symm_co_side(symm, e->v2->co) == SYMM_SIDE_KILL)) &&
633
/* The edge might be used by a face outside the input set */
634
if (BM_edge_is_wire(e))
635
BM_edge_kill(symm->bm, e);
639
/* Kill unused vertices */
640
BMO_ITER (v, &oiter, symm->op->slots_in, "input", BM_VERT) {
641
if (symm_co_side(symm, v->co) == SYMM_SIDE_KILL) {
642
if (BM_vert_edge_count(v) == 0)
643
BM_vert_kill(symm->bm, v);
648
void bmo_symmetrize_exec(BMesh *bm, BMOperator *op)
651
BMO_SymmDirection direction = BMO_slot_int_get(op->slots_in, "direction");
655
symm.axis = (ELEM(direction,
656
BMO_SYMMETRIZE_NEGATIVE_X,
657
BMO_SYMMETRIZE_POSITIVE_X) ? 0 :
659
BMO_SYMMETRIZE_NEGATIVE_Y,
660
BMO_SYMMETRIZE_POSITIVE_Y) ? 1 :
662
BMO_SYMMETRIZE_NEGATIVE_Z,
663
BMO_SYMMETRIZE_POSITIVE_Z) ? 2 : 0);
664
symm.direction = direction;
666
symm_verts_mirror(&symm);
667
symm_split_asymmetric_edges(&symm);
668
symm_mirror_edges(&symm);
669
symm_mirror_polygons(&symm);
670
symm_kill_unused(&symm);
672
BLI_ghash_free(symm.vert_symm_map, NULL, NULL);
673
BLI_ghash_free(symm.edge_split_map, NULL, NULL);
675
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out",
676
BM_ALL_NOLOOP, SYMM_OUTPUT_GEOM);