~ubuntu-branches/ubuntu/trusty/blender/trusty

« back to all changes in this revision

Viewing changes to source/blender/bmesh/operators/bmo_symmetrize.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-03-06 12:08:47 UTC
  • mfrom: (1.5.1) (14.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20130306120847-frjfaryb2zrotwcg
Tags: 2.66a-1ubuntu1
* Resynchronize with Debian (LP: #1076930, #1089256, #1052743, #999024,
  #1122888, #1147084)
* debian/control:
  - Lower build-depends on libavcodec-dev since we're not
    doing the libav9 transition in Ubuntu yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ***** BEGIN GPL LICENSE BLOCK *****
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 *
 
18
 * Contributor(s): Nicholas Bishop
 
19
 *
 
20
 * ***** END GPL LICENSE BLOCK *****
 
21
 */
 
22
 
 
23
#include "MEM_guardedalloc.h"
 
24
 
 
25
#include "BLI_array.h"
 
26
#include "BLI_math.h"
 
27
#include "BLI_utildefines.h"
 
28
 
 
29
#include "bmesh.h"
 
30
#include "intern/bmesh_operators_private.h"
 
31
 
 
32
enum {
 
33
        SYMM_OUTPUT_GEOM = (1 << 0)
 
34
};
 
35
 
 
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
 
39
 
 
40
typedef enum {
 
41
        /* Coordinate lies on the side being copied from */
 
42
        SYMM_SIDE_KEEP,
 
43
        /* Coordinate lies on the side being copied from and within the
 
44
         * axis threshold */
 
45
        SYMM_SIDE_AXIS,
 
46
        /* Coordinate lies on the side being copied to */
 
47
        SYMM_SIDE_KILL
 
48
} SymmSide;
 
49
 
 
50
typedef struct {
 
51
        BMesh *bm;
 
52
        BMOperator *op;
 
53
 
 
54
        int axis;
 
55
        BMO_SymmDirection direction;
 
56
 
 
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. */
 
60
        GHash *vert_symm_map;
 
61
 
 
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;
 
66
} Symm;
 
67
 
 
68
/* Return which side the coordinate lies on */
 
69
static SymmSide symm_co_side(const Symm *symm,
 
70
                             const float *co)
 
71
{
 
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))
 
77
        {
 
78
                comp = -comp;
 
79
        }
 
80
 
 
81
        if (comp >= 0) {
 
82
                if (comp < SYMM_AXIS_THRESHOLD)
 
83
                        return SYMM_SIDE_AXIS;
 
84
                else
 
85
                        return SYMM_SIDE_KEEP;
 
86
        }
 
87
        else
 
88
                return SYMM_SIDE_KILL;
 
89
}
 
90
 
 
91
/* Output vertices and the vert_map array */
 
92
static void symm_verts_mirror(Symm *symm)
 
93
{
 
94
        BMOIter oiter;
 
95
        BMVert *src_v, *dst_v;
 
96
 
 
97
        symm->vert_symm_map = BLI_ghash_ptr_new(AT);
 
98
 
 
99
        BMO_ITER (src_v, &oiter, symm->op->slots_in, "input", BM_VERT) {
 
100
                SymmSide side = symm_co_side(symm, src_v->co);
 
101
                float co[3];
 
102
 
 
103
                switch (side) {
 
104
                        case SYMM_SIDE_KEEP:
 
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];
 
108
 
 
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);
 
112
                                break;
 
113
 
 
114
                        case SYMM_SIDE_AXIS:
 
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);
 
119
                                break;
 
120
 
 
121
                        case SYMM_SIDE_KILL:
 
122
                                /* The vertex does not lie in the half-space being
 
123
                                 * copied from, nothing to do */
 
124
                                break;
 
125
                }
 
126
        }
 
127
}
 
128
 
 
129
static int symm_edge_crosses_axis(const Symm *symm, const BMEdge *e)
 
130
{
 
131
        const int sides[2] = {symm_co_side(symm, e->v1->co),
 
132
                                  symm_co_side(symm, e->v2->co)};
 
133
 
 
134
        return ((sides[0] != SYMM_SIDE_AXIS) &&
 
135
                (sides[1] != SYMM_SIDE_AXIS) &&
 
136
                (sides[0] != sides[1]));
 
137
}
 
138
 
 
139
/* Output edge split vertices for asymmetric edges and the edge_splits
 
140
 * mapping array */
 
141
static void symm_split_asymmetric_edges(Symm *symm)
 
142
{
 
143
        BMOIter oiter;
 
144
        BMEdge *e;
 
145
 
 
146
        symm->edge_split_map = BLI_ghash_ptr_new(AT);
 
147
 
 
148
        BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) {
 
149
                float flipped[3];
 
150
 
 
151
                copy_v3_v3(flipped, e->v1->co);
 
152
                flipped[symm->axis] = -flipped[symm->axis];
 
153
 
 
154
                if (symm_edge_crosses_axis(symm, e) &&
 
155
                    (!compare_v3v3(e->v2->co, flipped, SYMM_VERT_THRESHOLD)))
 
156
                {
 
157
                        /* Endpoints lie on opposite sides and are asymmetric */
 
158
 
 
159
                        BMVert *v;
 
160
                        float lambda = 0, edge_dir[3], co[3];
 
161
                        float plane_co[3][3][3] = {
 
162
                                /* axis == 0 */
 
163
                                {{0, 0, 0}, {0, 1, 0}, {0, 0, 1}},
 
164
                                /* axis == 1 */
 
165
                                {{0, 0, 0}, {1, 0, 0}, {0, 0, 1}},
 
166
                                /* axis == 2 */
 
167
                                {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}},
 
168
                        };
 
169
                        int r;
 
170
 
 
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,
 
175
                                               edge_dir,
 
176
                                               plane_co[symm->axis][0],
 
177
                                               plane_co[symm->axis][1],
 
178
                                               plane_co[symm->axis][2],
 
179
                                               &lambda, true);
 
180
                        BLI_assert(r);
 
181
 
 
182
                        madd_v3_v3v3fl(co, e->v1->co, edge_dir, lambda);
 
183
                        co[symm->axis] = 0;
 
184
 
 
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);
 
189
                }
 
190
        }
 
191
}
 
192
 
 
193
static void symm_mirror_edges(Symm *symm)
 
194
{
 
195
        BMOIter oiter;
 
196
        BMEdge *e;
 
197
 
 
198
        BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) {
 
199
                BMVert *v1 = NULL, *v2 = NULL;
 
200
                BMEdge *e_new;
 
201
 
 
202
                v1 = BLI_ghash_lookup(symm->vert_symm_map, e->v1);
 
203
                v2 = BLI_ghash_lookup(symm->vert_symm_map, e->v2);
 
204
 
 
205
                if (v1 && 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);
 
208
                }
 
209
                else if (v1 || v2) {
 
210
                        if (BLI_ghash_haskey(symm->edge_split_map, e)) {
 
211
                                BMVert *v_split = BLI_ghash_lookup(symm->edge_split_map, e);
 
212
 
 
213
                                /* Output the keep side of the split edge */
 
214
                                if (!v1) {
 
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);
 
217
                                        v1 = v_split;
 
218
                                }
 
219
                                else {
 
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);
 
222
                                        v2 = v_split;
 
223
                                }
 
224
 
 
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);
 
228
                        }
 
229
                }
 
230
        }
 
231
}
 
232
 
 
233
/****************************** SymmPoly ******************************/
 
234
 
 
235
typedef struct {
 
236
        /* Indices into the source mvert array (or -1 if not in that array) */
 
237
        BMVert **src_verts;
 
238
        /* Indices into the destination mvert array, these are vertices
 
239
         * created by an edge split (-1 for vertices not created by edge
 
240
         * split) */
 
241
        BMVert **edge_verts;
 
242
 
 
243
        /* Number of vertices in the polygon */
 
244
        int len;
 
245
 
 
246
        /* True only if none of the polygon's edges were split */
 
247
        bool already_symmetric;
 
248
 
 
249
        BMFace *src_face;
 
250
} SymmPoly;
 
251
 
 
252
static void symm_poly_with_splits(const Symm *symm,
 
253
                                  BMFace *f,
 
254
                                  SymmPoly *out)
 
255
{
 
256
        BMIter iter;
 
257
        BMLoop *l;
 
258
        int i;
 
259
 
 
260
        out->src_face = f;
 
261
 
 
262
        /* Count vertices and check for edge splits */
 
263
        out->len = f->len;
 
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)) {
 
267
                        out->len++;
 
268
                        out->already_symmetric = false;
 
269
                }
 
270
        }
 
271
 
 
272
        i = 0;
 
273
        BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
 
274
                BMVert *split = BLI_ghash_lookup(symm->edge_split_map, l->e);
 
275
 
 
276
                out->src_verts[i] = l->v;
 
277
                out->edge_verts[i] = NULL;
 
278
                i++;
 
279
 
 
280
                if (split) {
 
281
                        out->src_verts[i] = NULL;
 
282
                        out->edge_verts[i] = split;
 
283
                        i++;
 
284
                }
 
285
        }
 
286
}
 
287
 
 
288
static const float *symm_poly_co(const SymmPoly *sp, int v)
 
289
{
 
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;
 
294
        else
 
295
                return NULL;
 
296
}
 
297
 
 
298
static SymmSide symm_poly_co_side(const Symm *symm,
 
299
                                  const SymmPoly *sp,
 
300
                                  int v)
 
301
{
 
302
        return symm_co_side(symm, symm_poly_co(sp, v));
 
303
}
 
304
 
 
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)
 
308
{
 
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];
 
313
        else
 
314
                return NULL;
 
315
}
 
316
 
 
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,
 
320
                                    const SymmPoly *sp,
 
321
                                    int v)
 
322
{
 
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]);
 
328
                else
 
329
                        return sp->src_verts[v];
 
330
        }
 
331
        else
 
332
                return NULL;
 
333
}
 
334
 
 
335
static bool symm_poly_next_crossing(const Symm *symm,
 
336
                                    const SymmPoly *sp,
 
337
                                    int start,
 
338
                                    int *l1,
 
339
                                    int *l2)
 
340
{
 
341
        int i;
 
342
 
 
343
        for (i = 0; i < sp->len; i++) {
 
344
                (*l1) = (start + i) % sp->len;
 
345
                (*l2) = ((*l1) + 1) % sp->len;
 
346
 
 
347
                if ((symm_poly_co_side(symm, sp, *l1) == SYMM_SIDE_KILL) ^
 
348
                    (symm_poly_co_side(symm, sp, *l2) == SYMM_SIDE_KILL))
 
349
                {
 
350
                        return true;
 
351
                }
 
352
        }
 
353
 
 
354
        BLI_assert(!"symm_poly_next_crossing failed");
 
355
        return false;
 
356
}
 
357
 
 
358
static BMFace *symm_face_create_v(BMesh *bm, BMFace *example,
 
359
                                  BMVert **fv, BMEdge **fe, int len)
 
360
{
 
361
        BMFace *f_new;
 
362
        int i;
 
363
 
 
364
        /* TODO: calling symmetrize in dynamic-topology sculpt mode
 
365
         * frequently tries to create faces of length less than two,
 
366
         * should investigate further */
 
367
        if (len < 3)
 
368
                return NULL;
 
369
 
 
370
        for (i = 0; i < len; i++) {
 
371
                int j = (i + 1) % len;
 
372
                fe[i] = BM_edge_exists(fv[i], fv[j]);
 
373
                if (!fe[i]) {
 
374
                        fe[i] = BM_edge_create(bm, fv[i], fv[j], NULL, 0);
 
375
                        BMO_elem_flag_enable(bm, fe[i], SYMM_OUTPUT_GEOM);
 
376
                }
 
377
        }
 
378
        f_new = BM_face_create(bm, fv, fe, len, BM_CREATE_NO_DOUBLE);
 
379
        if (example)
 
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);
 
383
 
 
384
        return f_new;
 
385
}
 
386
 
 
387
static void symm_mesh_output_poly_zero_splits(Symm *symm,
 
388
                                              SymmPoly *sp,
 
389
                                              BMVert **fv,
 
390
                                              BMEdge **fe,
 
391
                                              int segment_len,
 
392
                                              int start)
 
393
{
 
394
        int i, j;
 
395
 
 
396
        j = 0;
 
397
 
 
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];
 
403
        }
 
404
 
 
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;
 
408
 
 
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]);
 
413
                }
 
414
        }
 
415
 
 
416
        symm_face_create_v(symm->bm, sp->src_face, fv, fe, j);
 
417
}
 
418
 
 
419
static void symm_mesh_output_poly_with_splits(Symm *symm,
 
420
                                              SymmPoly *sp,
 
421
                                              BMVert **fv,
 
422
                                              BMEdge **fe,
 
423
                                              int segment_len,
 
424
                                              int start)
 
425
{
 
426
        int i;
 
427
 
 
428
        /* Output the keep side of the input polygon */
 
429
 
 
430
        for (i = 0; i < segment_len; i++) {
 
431
                const int offset = (start + i) % sp->len;
 
432
                BMVert *v = symm_poly_dst(sp, offset);
 
433
 
 
434
                BLI_assert(v);
 
435
 
 
436
                fv[i] = v;
 
437
        }
 
438
 
 
439
        symm_face_create_v(symm->bm, sp->src_face, fv, fe, segment_len);
 
440
 
 
441
        /* Output the kill side of the input polygon */
 
442
 
 
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);
 
446
 
 
447
                fv[segment_len - i - 1] = v;
 
448
 
 
449
        }
 
450
 
 
451
        symm_face_create_v(symm->bm, sp->src_face, fv, fe, segment_len);
 
452
}
 
453
 
 
454
static void symm_mirror_polygons(Symm *symm)
 
455
{
 
456
        BMOIter oiter;
 
457
        BMFace *f;
 
458
        BMVert **pv = NULL;
 
459
        BMVert **fv = NULL;
 
460
        BMEdge **fe = NULL;
 
461
        BLI_array_declare(pv);
 
462
        BLI_array_declare(fv);
 
463
        BLI_array_declare(fe);
 
464
 
 
465
        BMO_ITER (f, &oiter, symm->op->slots_in, "input", BM_FACE) {
 
466
                BMIter iter;
 
467
                BMLoop *l;
 
468
                bool mirror_all = true, ignore_all = true;
 
469
 
 
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)
 
474
                                mirror_all = false;
 
475
                        else if (side == SYMM_SIDE_KEEP)
 
476
                                ignore_all = false;
 
477
                }
 
478
 
 
479
                if (mirror_all) {
 
480
                        int i;
 
481
 
 
482
                        /* Make a mirrored copy of the polygon */
 
483
 
 
484
                        BLI_array_empty(fv);
 
485
                        BLI_array_empty(fe);
 
486
                        BLI_array_grow_items(fv, f->len);
 
487
                        BLI_array_grow_items(fe, f->len);
 
488
 
 
489
                        i = f->len;
 
490
                        BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
 
491
                                i--;
 
492
 
 
493
                                if (symm_co_side(symm, l->v->co) == SYMM_SIDE_KEEP)
 
494
                                        fv[i] = BLI_ghash_lookup(symm->vert_symm_map, l->v);
 
495
                                else
 
496
                                        fv[i] = l->v;
 
497
                        }
 
498
 
 
499
                        symm_face_create_v(symm->bm, f, fv, fe, f->len);
 
500
                }
 
501
                else if (ignore_all) {
 
502
                        BM_face_kill(symm->bm, f);
 
503
                }
 
504
                else {
 
505
                        SymmPoly sp;
 
506
                        int l1, l2, l3, l4;
 
507
                        int double_l2, double_l3;
 
508
                        int segment_len;
 
509
 
 
510
                        BLI_array_empty(pv);
 
511
                        BLI_array_grow_items(pv, f->len * 4);
 
512
                        sp.src_verts = pv;
 
513
                        sp.edge_verts = pv + f->len * 2;
 
514
                        symm_poly_with_splits(symm, f, &sp);
 
515
 
 
516
                        /* Find first loop edge crossing the axis */
 
517
                        symm_poly_next_crossing(symm, &sp, 0, &l1, &l2);
 
518
 
 
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);
 
522
                        }
 
523
 
 
524
                        /* Find next crossing (keep to kill) */
 
525
                        symm_poly_next_crossing(symm, &sp, l2, &l3, &l4);
 
526
 
 
527
                        if (l2 == l3)
 
528
                                segment_len = 0;
 
529
                        else if (l2 < l3)
 
530
                                segment_len = l3 - l2 + 1;
 
531
                        else
 
532
                                segment_len = (sp.len - l2 + 1) + l3;
 
533
 
 
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;
 
536
 
 
537
                        /* Calculate number of new polygons/loops */
 
538
                        if (segment_len == 0) {
 
539
                        }
 
540
                        else if (sp.already_symmetric) {
 
541
                                int new_loops;
 
542
 
 
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;
 
547
                                else
 
548
                                        new_loops = segment_len * 2 - 1;
 
549
 
 
550
                                BLI_array_empty(fv);
 
551
                                BLI_array_empty(fe);
 
552
                                BLI_array_grow_items(fv, new_loops);
 
553
                                BLI_array_grow_items(fe, new_loops);
 
554
 
 
555
                                symm_mesh_output_poly_zero_splits(symm, &sp,
 
556
                                                                  fv, fe,
 
557
                                                                  segment_len, l2);
 
558
                                BM_face_kill(symm->bm, f);
 
559
                        }
 
560
                        else if (!double_l2 && !double_l3) {
 
561
                                BLI_array_empty(fv);
 
562
                                BLI_array_empty(fe);
 
563
                                BLI_array_grow_items(fv, segment_len);
 
564
                                BLI_array_grow_items(fe, segment_len);
 
565
 
 
566
                                symm_mesh_output_poly_with_splits(symm, &sp,
 
567
                                                                  fv, fe,
 
568
                                                                  segment_len,
 
569
                                                                  l2);
 
570
 
 
571
                                BM_face_kill(symm->bm, f);
 
572
                        }
 
573
                        else {
 
574
                                BLI_array_empty(fv);
 
575
                                BLI_array_empty(fe);
 
576
                                BLI_array_grow_items(fv, segment_len);
 
577
                                BLI_array_grow_items(fe, segment_len);
 
578
 
 
579
                                symm_mesh_output_poly_with_splits(symm, &sp,
 
580
                                                                  fv, fe,
 
581
                                                                  segment_len,
 
582
                                                                  l2);
 
583
 
 
584
                                BM_face_kill(symm->bm, f);
 
585
 
 
586
                                /* Output bridge triangle */
 
587
 
 
588
                                BLI_array_empty(fv);
 
589
                                BLI_array_empty(fe);
 
590
                                BLI_array_grow_items(fv, 3);
 
591
                                BLI_array_grow_items(fe, 3);
 
592
 
 
593
                                if (double_l2) {
 
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);
 
597
                                }
 
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);
 
602
                                }
 
603
 
 
604
                                BLI_assert(fv[0] && fv[1] && fv[2]);
 
605
 
 
606
                                symm_face_create_v(symm->bm, NULL, fv, fe, 3);
 
607
                        }
 
608
                }
 
609
        }
 
610
 
 
611
        BLI_array_free(pv);
 
612
        BLI_array_free(fv);
 
613
        BLI_array_free(fe);
 
614
}
 
615
 
 
616
/* Remove unused edges and vertices from the side being copied to */
 
617
static void symm_kill_unused(Symm *symm)
 
618
{
 
619
        BMOIter oiter;
 
620
        BMEdge *e;
 
621
        BMVert *v;
 
622
 
 
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)));
 
628
 
 
629
                if (((symm_co_side(symm, e->v1->co) == SYMM_SIDE_KILL) ||
 
630
                     (symm_co_side(symm, e->v2->co) == SYMM_SIDE_KILL)) &&
 
631
                    !symmetric)
 
632
                {
 
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);
 
636
                }
 
637
        }
 
638
 
 
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);
 
644
                }
 
645
        }
 
646
}
 
647
 
 
648
void bmo_symmetrize_exec(BMesh *bm, BMOperator *op)
 
649
{
 
650
        Symm symm;
 
651
        BMO_SymmDirection direction = BMO_slot_int_get(op->slots_in, "direction");
 
652
 
 
653
        symm.bm = bm;
 
654
        symm.op = op;
 
655
        symm.axis = (ELEM(direction,
 
656
                          BMO_SYMMETRIZE_NEGATIVE_X,
 
657
                          BMO_SYMMETRIZE_POSITIVE_X) ? 0 :
 
658
                     ELEM(direction,
 
659
                          BMO_SYMMETRIZE_NEGATIVE_Y,
 
660
                          BMO_SYMMETRIZE_POSITIVE_Y) ? 1 :
 
661
                     ELEM(direction,
 
662
                          BMO_SYMMETRIZE_NEGATIVE_Z,
 
663
                          BMO_SYMMETRIZE_POSITIVE_Z) ? 2 : 0);
 
664
        symm.direction = direction;
 
665
 
 
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);
 
671
 
 
672
        BLI_ghash_free(symm.vert_symm_map, NULL, NULL);
 
673
        BLI_ghash_free(symm.edge_split_map, NULL, NULL);
 
674
 
 
675
        BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out",
 
676
                                          BM_ALL_NOLOOP, SYMM_OUTPUT_GEOM);
 
677
}