Blender V4.3
bmo_triangulate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include "MEM_guardedalloc.h"
12
13#include "DNA_listBase.h"
14
15#include "BLI_listbase.h"
16#include "BLI_math_vector.h"
17#include "BLI_scanfill.h"
18#include "BLI_sort_utils.h"
19
20#include "bmesh.hh"
21#include "bmesh_tools.hh"
23
24#define ELE_NEW 1
25#define EDGE_MARK 4
26
28{
29 const int quad_method = BMO_slot_int_get(op->slots_in, "quad_method");
30 const int ngon_method = BMO_slot_int_get(op->slots_in, "ngon_method");
31
32 BMOpSlot *slot_facemap_out = BMO_slot_get(op->slots_out, "face_map.out");
33 BMOpSlot *slot_facemap_double_out = BMO_slot_get(op->slots_out, "face_map_double.out");
34
37
39 bm, quad_method, ngon_method, 4, true, op, slot_facemap_out, slot_facemap_double_out);
40
43}
44
45struct SortNormal {
46 float value; /* keep first */
47 float no[3];
48};
49
51{
52 const bool use_beauty = BMO_slot_bool_get(op->slots_in, "use_beauty");
53 const bool use_dissolve = BMO_slot_bool_get(op->slots_in, "use_dissolve");
54 BMOIter siter;
55 BMEdge *e;
56 ScanFillContext sf_ctx;
57 // ScanFillEdge *sf_edge; /* UNUSED */
58 GHash *sf_vert_map;
59 float normal[3];
60 const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS |
62 uint nors_tot;
63 bool calc_winding = false;
64
65 sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_len(op->slots_in, "edges"));
66
67 BMO_slot_vec_get(op->slots_in, "normal", normal);
68
69 BLI_scanfill_begin(&sf_ctx);
70
71 BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
72 ScanFillVert *sf_verts[2];
73 BMVert **e_verts = &e->v1;
74 uint i;
75
77
78 calc_winding = (calc_winding || BM_edge_is_boundary(e));
79
80 for (i = 0; i < 2; i++) {
81 if ((sf_verts[i] = static_cast<ScanFillVert *>(BLI_ghash_lookup(sf_vert_map, e_verts[i]))) ==
82 nullptr)
83 {
84 sf_verts[i] = BLI_scanfill_vert_add(&sf_ctx, e_verts[i]->co);
85 sf_verts[i]->tmp.p = e_verts[i];
86 BLI_ghash_insert(sf_vert_map, e_verts[i], sf_verts[i]);
87 }
88 }
89
90 /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, UNPACK2(sf_verts));
91 // sf_edge->tmp.p = e; /* UNUSED */
92 }
93 nors_tot = BLI_ghash_len(sf_vert_map);
94 BLI_ghash_free(sf_vert_map, nullptr, nullptr);
95
96 if (is_zero_v3(normal)) {
97 /* calculate the normal from the cross product of vert-edge pairs.
98 * Since we don't know winding, just accumulate */
99 ScanFillVert *sf_vert;
100 SortNormal *nors;
101 uint i;
102 bool is_degenerate = true;
103
104 nors = static_cast<SortNormal *>(MEM_mallocN(sizeof(*nors) * nors_tot, __func__));
105
106 for (sf_vert = static_cast<ScanFillVert *>(sf_ctx.fillvertbase.first), i = 0; sf_vert;
107 sf_vert = sf_vert->next, i++)
108 {
109 BMVert *v = static_cast<BMVert *>(sf_vert->tmp.p);
110 BMIter eiter;
111 BMEdge *e_pair[2];
112 uint e_index = 0;
113
114 nors[i].value = -1.0f;
115
116 /* only use if 'is_degenerate' stays true */
117 add_v3_v3(normal, v->no);
118
119 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
121 if (e_index == 2) {
122 e_index = 0;
123 break;
124 }
125 e_pair[e_index++] = e;
126 }
127 }
128
129 if (e_index == 2) {
130 float dir_a[3], dir_b[3];
131
132 is_degenerate = false;
133
134 sub_v3_v3v3(dir_a, v->co, BM_edge_other_vert(e_pair[0], v)->co);
135 sub_v3_v3v3(dir_b, v->co, BM_edge_other_vert(e_pair[1], v)->co);
136
137 cross_v3_v3v3(nors[i].no, dir_a, dir_b);
138 nors[i].value = len_squared_v3(nors[i].no);
139
140 /* only to get deterministic behavior (for initial normal) */
141 if (len_squared_v3(dir_a) > len_squared_v3(dir_b)) {
142 negate_v3(nors[i].no);
143 }
144 }
145 }
146
147 if (UNLIKELY(is_degenerate)) {
148 /* no vertices have 2 edges?
149 * in this case fall back to the average vertex normals */
150 }
151 else {
152 qsort(nors, nors_tot, sizeof(*nors), BLI_sortutil_cmp_float_reverse);
153
154 copy_v3_v3(normal, nors[0].no);
155 for (i = 0; i < nors_tot; i++) {
156 if (UNLIKELY(nors[i].value == -1.0f)) {
157 break;
158 }
159 if (dot_v3v3(normal, nors[i].no) < 0.0f) {
160 negate_v3(nors[i].no);
161 }
162 add_v3_v3(normal, nors[i].no);
163 }
164 normalize_v3(normal);
165 }
166
167 MEM_freeN(nors);
168 }
169 else {
170 calc_winding = false;
171 }
172
173 /* in this case we almost certainly have degenerate geometry,
174 * better set a fallback value as a last resort */
175 if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
176 normal[2] = 1.0f;
177 }
178
179 BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal);
180
181 /* if we have existing faces, base winding on those */
182 if (calc_winding) {
183 int winding_votes = 0;
184 LISTBASE_FOREACH (ScanFillFace *, sf_tri, &sf_ctx.fillfacebase) {
185 BMVert *v_tri[3] = {static_cast<BMVert *>(sf_tri->v1->tmp.p),
186 static_cast<BMVert *>(sf_tri->v2->tmp.p),
187 static_cast<BMVert *>(sf_tri->v3->tmp.p)};
188 uint i, i_prev;
189
190 for (i = 0, i_prev = 2; i < 3; i_prev = i++) {
191 e = BM_edge_exists(v_tri[i], v_tri[i_prev]);
193 winding_votes += (e->l->v == v_tri[i]) ? 1 : -1;
194 }
195 }
196 }
197
198 if (winding_votes < 0) {
199 LISTBASE_FOREACH (ScanFillFace *, sf_tri, &sf_ctx.fillfacebase) {
200 std::swap(sf_tri->v2, sf_tri->v3);
201 }
202 }
203 }
204
205 LISTBASE_FOREACH (ScanFillFace *, sf_tri, &sf_ctx.fillfacebase) {
206 BMFace *f;
207 BMLoop *l;
208 BMIter liter;
209
211 static_cast<BMVert *>(sf_tri->v1->tmp.p),
212 static_cast<BMVert *>(sf_tri->v2->tmp.p),
213 static_cast<BMVert *>(sf_tri->v3->tmp.p),
214 nullptr,
215 nullptr,
217
219 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
220 if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) {
222 }
223 }
224 }
225
226 BLI_scanfill_end(&sf_ctx);
227
228 if (use_beauty) {
229 BMOperator bmop;
230
231 BMO_op_initf(bm, &bmop, op->flag, "beautify_fill faces=%ff edges=%Fe", ELE_NEW, EDGE_MARK);
232 BMO_op_exec(bm, &bmop);
234 BMO_op_finish(bm, &bmop);
235 }
236
237 if (use_dissolve) {
238 BMEdge *e_next;
239 BMIter iter;
240
241 BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
243 /* in rare cases the edges face will have already been removed from the edge */
245 BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false);
246 if (f_new) {
248 BM_edge_kill(bm, e);
249 }
250 }
251 else if (e->l == nullptr) {
252 BM_edge_kill(bm, e);
253 }
254 else {
255 /* Edges with 1 or 3+ faces attached,
256 * most likely caused by a degenerate mesh. */
257 }
258 }
259 }
260 }
261
263}
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:702
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
#define LISTBASE_FOREACH(type, var, list)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void BLI_scanfill_begin(ScanFillContext *sf_ctx)
Definition scanfill.c:791
@ BLI_SCANFILL_CALC_LOOSE
@ BLI_SCANFILL_CALC_POLYS
@ BLI_SCANFILL_CALC_HOLES
struct ScanFillVert * BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3])
Definition scanfill.c:95
void BLI_scanfill_end(ScanFillContext *sf_ctx)
Definition scanfill.c:805
struct ScanFillEdge * BLI_scanfill_edge_add(ScanFillContext *sf_ctx, struct ScanFillVert *v1, struct ScanFillVert *v2)
Definition scanfill.c:117
unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, int flag, const float nor_proj[3])
Definition scanfill.c:825
int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_)
Definition sort_utils.c:39
unsigned int uint
#define UNPACK2(a)
#define UNLIKELY(x)
#define LIKELY(x)
These structs are the foundation for all linked lists in the library system.
Read Guarded memory(de)allocation.
@ BM_ELEM_TAG
BMFace * BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag)
Make Quad/Triangle.
void BM_edge_kill(BMesh *bm, BMEdge *e)
@ BM_CREATE_NO_DOUBLE
Definition bmesh_core.hh:26
#define BM_ITER_ELEM(ele, iter, data, itype)
@ BM_EDGES_OF_MESH
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
#define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMFace * BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
Faces Join Pair.
#define BM_FACE
#define BM_EDGE
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
#define BMO_edge_flag_test(bm, e, oflag)
void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3])
#define BMO_edge_flag_enable(bm, e, oflag)
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
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.
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const int min_vertices, const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out)
#define ELE_NEW
void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
#define EDGE_MARK
void bmo_triangulate_exec(BMesh *bm, BMOperator *op)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
struct BMEdge * e
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
float no[3]
void * first
ListBase fillvertbase
ListBase fillfacebase
struct ScanFillVert * next
union ScanFillVert::@114 tmp