Blender V5.0
bmo_connect_concave.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
18
19#include "MEM_guardedalloc.h"
20
21#include "BLI_alloca.h"
22#include "BLI_heap.h"
23#include "BLI_linklist.h"
24#include "BLI_math_geom.h"
25#include "BLI_math_vector.h"
26#include "BLI_memarena.h"
27#include "BLI_polyfill_2d.h"
29
30#include "bmesh.hh"
31
32#include "intern/bmesh_operators_private.hh" /* own include */
33
34#define EDGE_OUT (1 << 0)
35#define FACE_OUT (1 << 1)
36
37static int bm_edge_length_cmp(const void *a_, const void *b_)
38{
39 const BMEdge *e_a = static_cast<const BMEdge *>(*(const void **)a_);
40 const BMEdge *e_b = static_cast<const BMEdge *>(*(const void **)b_);
41
42 int e_a_concave = (BM_elem_flag_test(e_a->v1, BM_ELEM_TAG) &&
44 int e_b_concave = (BM_elem_flag_test(e_b->v1, BM_ELEM_TAG) &&
46
47 /* merge edges between concave edges last since these
48 * are most likely to remain and be the main dividers */
49 if (e_a_concave < e_b_concave) {
50 return -1;
51 }
52 if (e_a_concave > e_b_concave) {
53 return 1;
54 }
55
56 /* otherwise shortest edges last */
57 const float e_a_len = BM_edge_calc_length_squared(e_a);
58 const float e_b_len = BM_edge_calc_length_squared(e_b);
59 if (e_a_len < e_b_len) {
60 return 1;
61 }
62 if (e_a_len > e_b_len) {
63 return -1;
64 }
65 return 0;
66}
67
69 BMFace *f_base,
70 const float eps,
71
72 MemArena *pf_arena,
73 Heap *pf_heap)
74{
75 const int f_base_len = f_base->len;
76 int faces_array_tot = f_base_len - 3;
77 int edges_array_tot = f_base_len - 3;
78 BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
79 BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
80 const int quad_method = 0, ngon_method = 0; /* beauty */
81 LinkNode *faces_double = nullptr;
82
83 float normal[3];
84 BLI_assert(f_base->len > 3);
85
86 copy_v3_v3(normal, f_base->no);
87
89 f_base,
90 faces_array,
91 &faces_array_tot,
92 edges_array,
93 &edges_array_tot,
94 &faces_double,
95 quad_method,
96 ngon_method,
97 false,
98 pf_arena,
99 pf_heap);
100
101 BLI_assert(edges_array_tot <= f_base_len - 3);
102
103 if (faces_array_tot) {
104 int i;
105 for (i = 0; i < faces_array_tot; i++) {
106 BMFace *f = faces_array[i];
108 }
109 }
111
112 if (edges_array_tot) {
113 int i;
114
115 qsort(edges_array, edges_array_tot, sizeof(*edges_array), bm_edge_length_cmp);
116
117 for (i = 0; i < edges_array_tot; i++) {
118 BMLoop *l_pair[2];
119 BMEdge *e = edges_array[i];
121
122 if (BM_edge_is_contiguous(e) && BM_edge_loop_pair(e, &l_pair[0], &l_pair[1])) {
123 bool ok = true;
124 int j;
125 for (j = 0; j < 2; j++) {
126 BMLoop *l = l_pair[j];
127
128 /* check that merging the edge (on this side)
129 * wouldn't result in a convex face-loop.
130 *
131 * This is the (l->next, l->prev) we would have once joined.
132 */
133 float cross[3];
134 cross_tri_v3(cross, l->v->co, l->radial_next->next->next->v->co, l->prev->v->co);
135
136 if (dot_v3v3(cross, normal) <= eps) {
137 ok = false;
138 break;
139 }
140 }
141
142 if (ok) {
143 BMFace *f_double;
144 BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f};
145 f_new = BM_faces_join(bm, f_pair, 2, true, &f_double);
146 /* See #BM_faces_join note on callers asserting when `r_double` is non-null. */
147 BLI_assert_msg(f_double == nullptr,
148 "Doubled face detected at " AT ". Resulting mesh may be corrupt.");
149
150 if (f_new) {
152 }
153 }
154 }
155 }
156 }
157
158 BLI_heap_clear(pf_heap, nullptr);
159
160 while (faces_double) {
161 LinkNode *next = faces_double->next;
162 BM_face_kill(bm, static_cast<BMFace *>(faces_double->link));
163 MEM_freeN(faces_double);
164 faces_double = next;
165 }
166
167 return true;
168}
169
171{
172 bool is_concave = false;
173 if (f->len > 3) {
174 const BMLoop *l_iter, *l_first;
175
176 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
177 do {
178 if (BM_loop_is_convex(l_iter) == false) {
179 is_concave = true;
181 }
182 else {
184 }
185 } while ((l_iter = l_iter->next) != l_first);
186 }
187 return is_concave;
188}
189
191{
192 BMOIter siter;
193 BMFace *f;
194 bool changed = false;
195
196 MemArena *pf_arena;
197 Heap *pf_heap;
198
199 pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
201
202 BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
203 if (f->len > 3 && bm_face_convex_tag_verts(f)) {
204 if (bm_face_split_by_concave(bm, f, FLT_EPSILON, pf_arena, pf_heap)) {
205 changed = true;
206 }
207 }
208 }
209
210 if (changed) {
213 }
214
215 BLI_memarena_free(pf_arena);
216 BLI_heap_free(pf_heap, nullptr);
217}
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.cc:191
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.cc:171
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.cc:213
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:26
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
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
#define BLI_POLYFILL_ARENA_SIZE
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
#define AT
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_TAG
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del, BMFace **r_double)
Join Connected Faces.
void BM_face_kill(BMesh *bm, BMFace *f)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
BMesh * bm
#define BM_FACE
#define BM_EDGE
#define BMO_edge_flag_enable(bm, e, oflag)
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)
void BM_face_triangulate(BMesh *bm, BMFace *f, BMFace **r_faces_new, int *r_faces_new_tot, BMEdge **r_edges_new, int *r_edges_new_tot, LinkNode **r_faces_double, const int quad_method, const int ngon_method, const bool use_tag, MemArena *pf_arena, Heap *pf_heap)
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
float BM_edge_calc_length_squared(const BMEdge *e)
bool BM_loop_is_convex(const BMLoop *l)
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define FACE_OUT
Definition bmo_bridge.cc:28
#define EDGE_OUT
Definition bmo_bridge.cc:27
static bool bm_face_convex_tag_verts(BMFace *f)
void bmo_connect_verts_concave_exec(BMesh *bm, BMOperator *op)
static int bm_edge_length_cmp(const void *a_, const void *b_)
static bool bm_face_split_by_concave(BMesh *bm, BMFace *f_base, const float eps, MemArena *pf_arena, Heap *pf_heap)
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
const btScalar eps
Definition poly34.cpp:11
BMVert * v1
BMVert * v2
float no[3]
struct BMVert * v
struct BMFace * f
struct BMLoop * next
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
void * link
struct LinkNode * next
i
Definition text_draw.cc:230