Blender V4.3
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
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#include "BLI_utildefines.h"
30
31#include "bmesh.hh"
32
33#include "intern/bmesh_operators_private.hh" /* own include */
34
35#define EDGE_OUT (1 << 0)
36#define FACE_OUT (1 << 1)
37
38static int bm_edge_length_cmp(const void *a_, const void *b_)
39{
40 const BMEdge *e_a = static_cast<const BMEdge *>(*(const void **)a_);
41 const BMEdge *e_b = static_cast<const BMEdge *>(*(const void **)b_);
42
43 int e_a_concave = (BM_elem_flag_test(e_a->v1, BM_ELEM_TAG) &&
45 int e_b_concave = (BM_elem_flag_test(e_b->v1, BM_ELEM_TAG) &&
47
48 /* merge edges between concave edges last since these
49 * are most likely to remain and be the main dividers */
50 if (e_a_concave < e_b_concave) {
51 return -1;
52 }
53 if (e_a_concave > e_b_concave) {
54 return 1;
55 }
56
57 /* otherwise shortest edges last */
58 const float e_a_len = BM_edge_calc_length_squared(e_a);
59 const float e_b_len = BM_edge_calc_length_squared(e_b);
60 if (e_a_len < e_b_len) {
61 return 1;
62 }
63 if (e_a_len > e_b_len) {
64 return -1;
65 }
66 return 0;
67}
68
70 BMFace *f_base,
71 const float eps,
72
73 MemArena *pf_arena,
74 Heap *pf_heap)
75{
76 const int f_base_len = f_base->len;
77 int faces_array_tot = f_base_len - 3;
78 int edges_array_tot = f_base_len - 3;
79 BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
80 BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
81 const int quad_method = 0, ngon_method = 0; /* beauty */
82 LinkNode *faces_double = nullptr;
83
84 float normal[3];
85 BLI_assert(f_base->len > 3);
86
87 copy_v3_v3(normal, f_base->no);
88
90 f_base,
91 faces_array,
92 &faces_array_tot,
93 edges_array,
94 &edges_array_tot,
95 &faces_double,
96 quad_method,
97 ngon_method,
98 false,
99 pf_arena,
100 pf_heap);
101
102 BLI_assert(edges_array_tot <= f_base_len - 3);
103
104 if (faces_array_tot) {
105 int i;
106 for (i = 0; i < faces_array_tot; i++) {
107 BMFace *f = faces_array[i];
109 }
110 }
112
113 if (edges_array_tot) {
114 int i;
115
116 qsort(edges_array, edges_array_tot, sizeof(*edges_array), bm_edge_length_cmp);
117
118 for (i = 0; i < edges_array_tot; i++) {
119 BMLoop *l_pair[2];
120 BMEdge *e = edges_array[i];
122
123 if (BM_edge_is_contiguous(e) && BM_edge_loop_pair(e, &l_pair[0], &l_pair[1])) {
124 bool ok = true;
125 int j;
126 for (j = 0; j < 2; j++) {
127 BMLoop *l = l_pair[j];
128
129 /* check that merging the edge (on this side)
130 * wouldn't result in a convex face-loop.
131 *
132 * This is the (l->next, l->prev) we would have once joined.
133 */
134 float cross[3];
136
137 if (dot_v3v3(cross, normal) <= eps) {
138 ok = false;
139 break;
140 }
141 }
142
143 if (ok) {
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);
146 if (f_new) {
148 }
149 }
150 }
151 }
152 }
153
154 BLI_heap_clear(pf_heap, nullptr);
155
156 while (faces_double) {
157 LinkNode *next = faces_double->next;
158 BM_face_kill(bm, static_cast<BMFace *>(faces_double->link));
159 MEM_freeN(faces_double);
160 faces_double = next;
161 }
162
163 return true;
164}
165
167{
168 bool is_concave = false;
169 if (f->len > 3) {
170 const BMLoop *l_iter, *l_first;
171
172 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
173 do {
174 if (BM_loop_is_convex(l_iter) == false) {
175 is_concave = true;
177 }
178 else {
180 }
181 } while ((l_iter = l_iter->next) != l_first);
182 }
183 return is_concave;
184}
185
187{
188 BMOIter siter;
189 BMFace *f;
190 bool changed = false;
191
192 MemArena *pf_arena;
193 Heap *pf_heap;
194
195 pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
197
198 BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
199 if (f->len > 3 && bm_face_convex_tag_verts(f)) {
200 if (bm_face_split_by_concave(bm, f, FLT_EPSILON, pf_arena, pf_heap)) {
201 changed = true;
202 }
203 }
204 }
205
206 if (changed) {
209 }
210
211 BLI_memarena_free(pf_arena);
212 BLI_heap_free(pf_heap, nullptr);
213}
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.c:192
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.c:172
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.c:214
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:24
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
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_POLYFILL_ARENA_SIZE
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
Read Guarded memory(de)allocation.
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
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)
ATTR_WARN_UNUSED_RESULT 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
static bool bm_face_convex_tag_verts(BMFace *f)
#define FACE_OUT
#define EDGE_OUT
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)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float cross(const float2 a, const float2 b)
static ulong * next
const btScalar eps
Definition poly34.cpp:11
BMVert * v1
BMVert * v2
float no[3]
struct BMVert * v
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
void * link
struct LinkNode * next