~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2014-02-19 11:24:23 UTC
  • mfrom: (14.2.23 sid)
  • Revision ID: package-import@ubuntu.com-20140219112423-rkmaz2m7ha06d4tk
Tags: 2.69-3ubuntu1
* Merge with Debian; remaining changes:
  - Configure without OpenImageIO on armhf, as it is not available on
    Ubuntu.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
 
33
33
#include "BLI_math.h"
34
34
#include "BLI_array.h"
 
35
#include "BLI_alloca.h"
35
36
#include "BLI_memarena.h"
36
37
#include "BKE_customdata.h"
37
38
 
42
43
#define ELE_NEW         1
43
44
 
44
45
 
45
 
 
46
 
/* -------------------------------------------------------------------- */
47
 
/* Inset Individual */
48
 
 
49
 
 
50
 
/* Holds Per-Face Inset Edge Data */
51
 
typedef struct EdgeInsetInfo {
52
 
        float no[3];
53
 
        BMEdge *e_old;
54
 
        BMEdge *e_new;
55
 
} EdgeInsetInfo;
56
 
 
57
 
/**
58
 
 * Individual Face Inset.
59
 
 * Find all tagged faces (f), duplicate edges around faces, inset verts of
60
 
 * created edges, create new faces between old and new edges, fill face
61
 
 * between connected new edges, kill old face (f).
62
 
 */
63
 
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
64
 
{
65
 
        BMEdge **f_edges = NULL;
66
 
        BMVert **f_verts = NULL;
67
 
        BMFace *f;
68
 
 
69
 
        BMOIter oiter;
70
 
        EdgeInsetInfo *eiinfo_arr = NULL;
71
 
 
72
 
        BLI_array_declare(eiinfo_arr);
73
 
        BLI_array_declare(f_edges);
74
 
        BLI_array_declare(f_verts);
75
 
 
76
 
        const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
77
 
        const float depth = BMO_slot_float_get(op->slots_in, "depth");
78
 
        const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
79
 
        const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
80
 
        const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
81
 
 
82
 
        /* Only tag faces in slot */
83
 
        BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
84
 
 
85
 
        BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
86
 
 
87
 
        BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) {
88
 
                BMFace *f_new_inner;
89
 
                BMLoop *l_iter, *l_first;
90
 
                BMLoop *l_iter_inner = NULL;
91
 
                int i;
92
 
 
93
 
                BLI_array_empty(f_verts);
94
 
                BLI_array_empty(f_edges);
95
 
                BLI_array_empty(eiinfo_arr);
96
 
                BLI_array_grow_items(f_verts, f->len);
97
 
                BLI_array_grow_items(f_edges, f->len);
98
 
                BLI_array_grow_items(eiinfo_arr, f->len);
99
 
 
100
 
                /* create verts */
101
 
                i = 0;
102
 
                l_iter = l_first = BM_FACE_FIRST_LOOP(f);
103
 
                do {
104
 
                        f_verts[i] = BM_vert_create(bm, l_iter->v->co, l_iter->v, 0);
105
 
                        i++;
106
 
                } while ((l_iter = l_iter->next) != l_first);
107
 
 
108
 
                /* make edges */
109
 
                i = 0;
110
 
                l_iter = l_first;
111
 
                do {
112
 
                        f_edges[i] = BM_edge_create(bm, f_verts[i], f_verts[(i + 1) % f->len], l_iter->e, 0);
113
 
 
114
 
                        eiinfo_arr[i].e_new = f_edges[i];
115
 
                        eiinfo_arr[i].e_old = l_iter->e;
116
 
                        BM_edge_calc_face_tangent(l_iter->e, l_iter, eiinfo_arr[i].no);
117
 
 
118
 
                        /* Tagging (old elements) required when iterating over edges
119
 
                         * connected to verts for translation vector calculation */
120
 
                        BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
121
 
                        BM_elem_index_set(l_iter->e, i);  /* set_dirty! */
122
 
                        i++;
123
 
                } while ((l_iter = l_iter->next) != l_first);
124
 
                /* done with edges */
125
 
 
126
 
                bm->elem_index_dirty |= BM_EDGE;
127
 
 
128
 
                /* Calculate translation vector for new  */
129
 
                l_iter = l_first;
130
 
                do {
131
 
                        EdgeInsetInfo *ei_prev = &eiinfo_arr[BM_elem_index_get(l_iter->prev->e)];
132
 
                        EdgeInsetInfo *ei_next = &eiinfo_arr[BM_elem_index_get(l_iter->e)];
133
 
                        float tvec[3];
134
 
                        float v_new_co[3];
135
 
                        int index = 0;
136
 
 
137
 
                        add_v3_v3v3(tvec, ei_prev->no, ei_next->no);
138
 
                        normalize_v3(tvec);
139
 
 
140
 
                        /* l->e is traversed in order */
141
 
                        index = BM_elem_index_get(l_iter->e);
142
 
 
143
 
                        copy_v3_v3(v_new_co, eiinfo_arr[index].e_new->v1->co);
144
 
 
145
 
                        if (use_even_offset) {
146
 
                                mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(ei_prev->no,  ei_next->no) / 2.0f));
147
 
                        }
148
 
 
149
 
                        /* Modify vertices and their normals */
150
 
                        if (use_relative_offset) {
151
 
                                mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
152
 
                        }
153
 
 
154
 
                        madd_v3_v3fl(v_new_co, tvec, thickness);
155
 
 
156
 
                        /* Set normal, add depth and write new vertex position*/
157
 
                        copy_v3_v3(eiinfo_arr[index].e_new->v1->no, f->no);
158
 
 
159
 
                        madd_v3_v3fl(v_new_co, f->no, depth);
160
 
 
161
 
                        copy_v3_v3(eiinfo_arr[index].e_new->v1->co, v_new_co);
162
 
                } while ((l_iter = l_iter->next) != l_first);
163
 
 
164
 
 
165
 
                /* Create New Inset Faces */
166
 
                f_new_inner = BM_face_create(bm, f_verts, f_edges, f->len, 0);
167
 
                BLI_assert(f_new_inner != NULL);  /* no reason it should fail */
168
 
 
169
 
 
170
 
                // Don't tag, gives more useful inner/outer select option
171
 
                // BMO_elem_flag_enable(bm, f_new_inner, ELE_NEW);
172
 
 
173
 
 
174
 
                /* Copy Face Data */
175
 
                /* interpolate loop data or just stretch */
176
 
                if (use_interpolate) {
177
 
                        BM_face_interp_from_face(bm, f_new_inner, f, true);
178
 
                }
179
 
                else {
180
 
                        BM_elem_attrs_copy(bm, bm, f, f_new_inner);
181
 
                }
182
 
 
183
 
                l_iter_inner = BM_FACE_FIRST_LOOP(f_new_inner);
184
 
                l_iter = l_first;
185
 
                do {
186
 
                        BMFace *f_new_outer;
187
 
 
188
 
                        BMLoop *l_a;
189
 
                        BMLoop *l_b;
190
 
 
191
 
                        if (use_interpolate == false) {
192
 
                                BM_elem_attrs_copy(bm, bm, l_iter, l_iter_inner);
193
 
                        }
194
 
 
195
 
                        f_new_outer = BM_face_create_quad_tri(bm,
196
 
                                                              l_iter->v,
197
 
                                                              l_iter->next->v,
198
 
                                                              l_iter_inner->next->v,
199
 
                                                              l_iter_inner->v,
200
 
                                                              f, false);
201
 
 
202
 
                        BLI_assert(f_new_outer != NULL);  /* no reason it should fail */
203
 
 
204
 
                        BM_elem_attrs_copy(bm, bm, f, f_new_outer);
205
 
                        BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
206
 
                        BM_elem_flag_enable(f_new_outer, BM_ELEM_TAG);
207
 
 
208
 
                        /* Copy Loop Data */
209
 
                        l_a = BM_FACE_FIRST_LOOP(f_new_outer);
210
 
                        l_b = l_a->next;
211
 
 
212
 
                        /* first pair */
213
 
                        BM_elem_attrs_copy(bm, bm, l_iter, l_a);
214
 
                        BM_elem_attrs_copy(bm, bm,  l_iter->next, l_b);
215
 
 
216
 
 
217
 
                        /* Move to the last two loops in new face */
218
 
                        l_a = l_b->next;
219
 
                        l_b = l_a->next;
220
 
 
221
 
                        /* This loop should always have >1 radials
222
 
                         * (associated edge connects new and old face) */
223
 
                        BM_elem_attrs_copy(bm, bm, l_iter_inner, l_b);
224
 
                        BM_elem_attrs_copy(bm, bm, use_interpolate ? l_iter_inner->next : l_iter->next, l_a);
225
 
 
226
 
                } while ((l_iter_inner = l_iter_inner->next),
227
 
                         (l_iter = l_iter->next) != l_first);
228
 
 
229
 
                BM_face_kill(bm, f);
230
 
        }
231
 
 
232
 
        /* we could flag new edges/verts too, is it useful? */
233
 
        BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
234
 
 
235
 
        BLI_array_free(f_verts);
236
 
        BLI_array_free(f_edges);
237
 
        BLI_array_free(eiinfo_arr);
238
 
}
239
 
 
240
 
 
241
 
 
242
 
/* -------------------------------------------------------------------- */
243
 
/* Inset Region */
244
 
 
245
 
typedef struct SplitEdgeInfo {
246
 
        float   no[3];
247
 
        float   length;
248
 
        BMEdge *e_old;
249
 
        BMEdge *e_new;
250
 
        BMLoop *l;
251
 
} SplitEdgeInfo;
252
 
 
 
46
/* -------------------------------------------------------------------- */
 
47
/* Generic Interp Face (use for both types of inset) */
253
48
 
254
49
/**
255
50
 * Interpolation, this is more complex for regions since we're not creating new faces
277
72
        void *axis_mat     = iface->axis_mat;
278
73
        int i;
279
74
 
 
75
        BLI_assert(BM_face_is_normal_valid(f));
 
76
 
280
77
        axis_dominant_v3_to_m3(axis_mat, f->no);
281
78
 
282
79
        iface->f = f;
310
107
}
311
108
 
312
109
 
 
110
/* -------------------------------------------------------------------- */
 
111
/* Inset Individual */
 
112
 
 
113
static void bmo_face_inset_individual(
 
114
        BMesh *bm, BMFace *f, MemArena *interp_arena,
 
115
        const float thickness, const float depth,
 
116
        const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate)
 
117
{
 
118
        InterpFace *iface = NULL;
 
119
 
 
120
        /* stores verts split away from the face (aligned with face verts) */
 
121
        BMVert **verts = BLI_array_alloca(verts, f->len);
 
122
        /* store edge normals (aligned with face-loop-edges) */
 
123
        float (*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len);
 
124
        float (*coords)[3] = BLI_array_alloca(coords, f->len);
 
125
 
 
126
        BMLoop *l_iter, *l_first;
 
127
        BMLoop *l_other;
 
128
        unsigned int i;
 
129
        float e_length_prev;
 
130
 
 
131
        l_first = BM_FACE_FIRST_LOOP(f);
 
132
 
 
133
        /* split off all loops */
 
134
        l_iter = l_first;
 
135
        i = 0;
 
136
        do {
 
137
                BMVert *v_other = l_iter->v;
 
138
                BMVert *v_sep = BM_face_loop_separate(bm, l_iter);
 
139
                if (v_sep == v_other) {
 
140
                        v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
 
141
                }
 
142
                verts[i] = v_other;
 
143
 
 
144
                /* unrelated to splitting, but calc here */
 
145
                BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]);
 
146
        } while (i++, ((l_iter = l_iter->next) != l_first));
 
147
 
 
148
 
 
149
        /* build rim faces */
 
150
        l_iter = l_first;
 
151
        i = 0;
 
152
        do {
 
153
                BMFace *f_new_outer;
 
154
                BMVert *v_other = verts[i];
 
155
                BMVert *v_other_next = verts[(i + 1) % f->len];
 
156
 
 
157
                BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE);
 
158
                (void)e_other;
 
159
 
 
160
                f_new_outer = BM_face_create_quad_tri(bm,
 
161
                                                      v_other,
 
162
                                                      v_other_next,
 
163
                                                      l_iter->next->v,
 
164
                                                      l_iter->v,
 
165
                                                      f, BM_CREATE_NOP);
 
166
                BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
 
167
 
 
168
                /* copy loop data */
 
169
                l_other = l_iter->radial_next;
 
170
                BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev);
 
171
                BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next);
 
172
 
 
173
                if (use_interpolate == false) {
 
174
                        BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
 
175
                        BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
 
176
                }
 
177
        } while (i++, ((l_iter = l_iter->next) != l_first));
 
178
 
 
179
        /* hold interpolation values */
 
180
        if (use_interpolate) {
 
181
                iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
 
182
                bm_interp_face_store(iface, bm, f, interp_arena);
 
183
        }
 
184
 
 
185
        /* Calculate translation vector for new */
 
186
        l_iter = l_first;
 
187
        i = 0;
 
188
 
 
189
        if (depth != 0.0f) {
 
190
                e_length_prev = BM_edge_calc_length(l_iter->prev->e);
 
191
        }
 
192
 
 
193
        do {
 
194
                const float *eno_prev = edge_nors[(i ? i : f->len) - 1];
 
195
                const float *eno_next = edge_nors[i];
 
196
                float tvec[3];
 
197
                float v_new_co[3];
 
198
 
 
199
                add_v3_v3v3(tvec, eno_prev, eno_next);
 
200
                normalize_v3(tvec);
 
201
 
 
202
                copy_v3_v3(v_new_co, l_iter->v->co);
 
203
 
 
204
                if (use_even_offset) {
 
205
                        mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(eno_prev,  eno_next) / 2.0f));
 
206
                }
 
207
 
 
208
                /* Modify vertices and their normals */
 
209
                if (use_relative_offset) {
 
210
                        mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
 
211
                }
 
212
 
 
213
                madd_v3_v3fl(v_new_co, tvec, thickness);
 
214
 
 
215
                /* Set normal, add depth and write new vertex position*/
 
216
                copy_v3_v3(l_iter->v->no, f->no);
 
217
 
 
218
                if (depth != 0.0f) {
 
219
                        const float e_length = BM_edge_calc_length(l_iter->e);
 
220
                        const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f);
 
221
                        e_length_prev = e_length;
 
222
 
 
223
                        madd_v3_v3fl(v_new_co, f->no, fac);
 
224
                }
 
225
 
 
226
 
 
227
 
 
228
                copy_v3_v3(coords[i], v_new_co);
 
229
        } while (i++, ((l_iter = l_iter->next) != l_first));
 
230
 
 
231
        /* update the coords */
 
232
        l_iter = l_first;
 
233
        i = 0;
 
234
        do {
 
235
                copy_v3_v3(l_iter->v->co, coords[i]);
 
236
        } while (i++, ((l_iter = l_iter->next) != l_first));
 
237
 
 
238
 
 
239
        if (use_interpolate) {
 
240
                BM_face_interp_from_face_ex(bm, iface->f, iface->f, true,
 
241
                                            iface->blocks_l, iface->blocks_v, iface->cos_2d, iface->axis_mat);
 
242
 
 
243
                /* build rim faces */
 
244
                l_iter = l_first;
 
245
                do {
 
246
                        /* copy loop data */
 
247
                        l_other = l_iter->radial_next;
 
248
 
 
249
                        BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
 
250
                        BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
 
251
                } while ((l_iter = l_iter->next) != l_first);
 
252
 
 
253
                bm_interp_face_free(iface, bm);
 
254
        }
 
255
}
 
256
 
 
257
 
 
258
/**
 
259
 * Individual Face Inset.
 
260
 * Find all tagged faces (f), duplicate edges around faces, inset verts of
 
261
 * created edges, create new faces between old and new edges, fill face
 
262
 * between connected new edges, kill old face (f).
 
263
 */
 
264
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
 
265
{
 
266
        BMFace *f;
 
267
 
 
268
        BMOIter oiter;
 
269
        MemArena *interp_arena = NULL;
 
270
 
 
271
        const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
 
272
        const float depth = BMO_slot_float_get(op->slots_in, "depth");
 
273
        const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
 
274
        const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
 
275
        const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
 
276
 
 
277
        /* Only tag faces in slot */
 
278
        BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
 
279
 
 
280
        BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
 
281
 
 
282
        if (use_interpolate) {
 
283
                interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
 
284
        }
 
285
 
 
286
        BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
 
287
                bmo_face_inset_individual(
 
288
                        bm, f, interp_arena,
 
289
                        thickness, depth,
 
290
                        use_even_offset, use_relative_offset, use_interpolate);
 
291
 
 
292
                if (use_interpolate) {
 
293
                        BLI_memarena_clear(interp_arena);
 
294
                }
 
295
        }
 
296
 
 
297
        /* we could flag new edges/verts too, is it useful? */
 
298
        BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
 
299
 
 
300
        if (use_interpolate) {
 
301
                BLI_memarena_free(interp_arena);
 
302
        }
 
303
}
 
304
 
 
305
 
 
306
 
 
307
/* -------------------------------------------------------------------- */
 
308
/* Inset Region */
 
309
 
 
310
typedef struct SplitEdgeInfo {
 
311
        float   no[3];
 
312
        float   length;
 
313
        BMEdge *e_old;
 
314
        BMEdge *e_new;
 
315
        BMLoop *l;
 
316
} SplitEdgeInfo;
 
317
 
313
318
/**
314
319
 * return the tag loop where there is...
315
320
 * - only 1 tagged face attached to this edge.
348
353
        }
349
354
}
350
355
 
 
356
static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info)
 
357
{
 
358
        BMIter iter;
 
359
        BMEdge *e;
 
360
 
 
361
        float len = 0.0f;
 
362
        int tot = 0;
 
363
 
 
364
 
 
365
        BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
 
366
                const int i = BM_elem_index_get(e);
 
367
                if (i != -1) {
 
368
                        len += edge_info[i].length;
 
369
                        tot++;
 
370
                }
 
371
        }
 
372
 
 
373
        BLI_assert(tot != 0);
 
374
        return len / (float)tot;
 
375
}
 
376
 
351
377
/**
352
378
 * implementation is as follows...
353
379
 *
455
481
 
456
482
 
457
483
                /* run the separate arg */
458
 
                bmesh_edge_separate(bm, es->e_old, es->l);
 
484
                bmesh_edge_separate(bm, es->e_old, es->l, false);
459
485
 
460
486
                /* calc edge-split info */
461
487
                es->e_new = es->l->e;
463
489
 
464
490
                if (es->e_new == es->e_old) { /* happens on boundary edges */
465
491
                        /* take care here, we're creating this double edge which _must_ have its verts replaced later on */
466
 
                        es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, 0);
 
492
                        es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP);
467
493
                }
468
494
 
469
495
                /* store index back to original in 'edge_info' */
506
532
 
507
533
                mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co);
508
534
 
509
 
                v1 = BM_vert_create(bm, tvec, NULL);
510
 
                v2 = BM_vert_create(bm, tvec, NULL);
 
535
                v1 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
 
536
                v2 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
511
537
                madd_v3_v3fl(v2->co, es->no, 0.1f);
512
538
                BM_edge_create(bm, v1, v2, NULL, 0);
513
539
        }
533
559
                                /* disable touching twice, this _will_ happen if the flags not disabled */
534
560
                                BM_elem_flag_disable(v, BM_ELEM_TAG);
535
561
 
536
 
                                bmesh_vert_separate(bm, v, &vout, &r_vout_len);
 
562
                                bmesh_vert_separate(bm, v, &vout, &r_vout_len, false);
537
563
                                v = NULL; /* don't use again */
538
564
 
539
565
                                /* in some cases the edge doesn't split off */
785
811
#endif
786
812
                /* no need to check doubles, we KNOW there won't be any */
787
813
                /* yes - reverse face is correct in this case */
788
 
                f = BM_face_create_quad_tri_v(bm, varr, j, es->l->f, false);
 
814
                f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
789
815
                BMO_elem_flag_enable(bm, f, ELE_NEW);
790
816
 
791
817
                /* copy for loop data, otherwise UV's and vcols are no good.
794
820
#if 0
795
821
                /* don't use this because face boundaries have no adjacent loops and won't be filled in.
796
822
                 * instead copy from the opposite side with the code below */
797
 
                BM_face_copy_shared(bm, f);
 
823
                BM_face_copy_shared(bm, f, NULL, NULL);
798
824
#else
799
825
                {
800
826
                        /* 2 inner loops on the edge between the new face and the original */
892
918
                BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
893
919
                        if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
894
920
                                const float fac = (depth *
895
 
                                                   (use_relative_offset ? BM_vert_calc_mean_tagged_edge_length(v) : 1.0f) *
 
921
                                                   (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) *
896
922
                                                   (use_even_boundry    ? BM_vert_calc_shell_factor(v) : 1.0f));
897
923
                                madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
898
924
                        }