Blender V4.3
scanfill_utils.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <limits.h>
10#include <math.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_ghash.h"
18#include "BLI_listbase.h"
19#include "BLI_math_geom.h"
20#include "BLI_math_vector.h"
21#include "BLI_utildefines.h"
22
23#include "BLI_scanfill.h" /* own include */
24
25#include "BLI_strict_flags.h" /* Keep last. */
26
31
32typedef struct ScanFillIsect {
34 float co[3];
35
36 /* newly created vertex */
39
40#define V_ISISECT 1
41#define E_ISISECT 1
42#define E_ISDELETE 2
43
44#define EFLAG_SET(eed, val) \
45 { \
46 CHECK_TYPE(eed, ScanFillEdge *); \
47 (eed)->user_flag = (eed)->user_flag | (uint)val; \
48 } \
49 (void)0
50#if 0
51# define EFLAG_CLEAR(eed, val) \
52 { \
53 CHECK_TYPE(eed, ScanFillEdge *); \
54 (eed)->user_flag = (eed)->user_flag & ~(uint)val; \
55 } \
56 (void)0
57#endif
58
59#define VFLAG_SET(eve, val) \
60 { \
61 CHECK_TYPE(eve, ScanFillVert *); \
62 (eve)->user_flag = (eve)->user_flag | (uint)val; \
63 } \
64 (void)0
65#if 0
66# define VFLAG_CLEAR(eve, val) \
67 { \
68 CHECK_TYPE(eve, ScanFillVert *); \
69 (eve)->user_flags = (eve)->user_flag & ~(uint)val; \
70 } \
71 (void)0
72#endif
73
74#if 0
75void BLI_scanfill_obj_dump(ScanFillContext *sf_ctx)
76{
77 FILE *f = fopen("test.obj", "w");
78 uint i = 1;
79
80 ScanFillVert *eve;
81 ScanFillEdge *eed;
82
83 for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next, i++) {
84 fprintf(f, "v %f %f %f\n", UNPACK3(eve->co));
85 eve->keyindex = i;
86 }
87 for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
88 fprintf(f, "f %d %d\n", eed->v1->keyindex, eed->v2->keyindex);
89 }
90 fclose(f);
91}
92#endif
93
95{
96 ListBase *e_ls;
97 void **val_p;
98
99 if (!BLI_ghash_ensure_p(isect_hash, eed, &val_p)) {
100 *val_p = MEM_callocN(sizeof(ListBase), __func__);
101 }
102 e_ls = *val_p;
103
104 return e_ls;
105}
106
108{
109 ListBase *e_ls;
110 LinkData *isect_link;
111 e_ls = edge_isect_ls_ensure(isect_hash, eed);
112 isect_link = MEM_callocN(sizeof(*isect_link), __func__);
113 isect_link->data = isect;
114 EFLAG_SET(eed, E_ISISECT);
115 BLI_addtail(e_ls, isect_link);
116 return e_ls;
117}
118
119static int edge_isect_ls_sort_cb(void *thunk, const void *def_a_ptr, const void *def_b_ptr)
120{
121 const float *co = thunk;
122
123 const ScanFillIsect *i_a = ((const LinkData *)def_a_ptr)->data;
124 const ScanFillIsect *i_b = ((const LinkData *)def_b_ptr)->data;
125 const float a = len_squared_v2v2(co, i_a->co);
126 const float b = len_squared_v2v2(co, i_b->co);
127
128 if (a > b) {
129 return -1;
130 }
131
132 return (a < b);
133}
134
135static ScanFillEdge *edge_step(PolyInfo *poly_info,
136 const ushort poly_nr,
137 ScanFillVert *v_prev,
138 ScanFillVert *v_curr,
139 ScanFillEdge *e_curr)
140{
141 ScanFillEdge *eed;
142
143 BLI_assert(ELEM(v_prev, e_curr->v1, e_curr->v2));
144 BLI_assert(ELEM(v_curr, e_curr->v1, e_curr->v2));
145
146 eed = (e_curr->next && e_curr != poly_info[poly_nr].edge_last) ? e_curr->next :
147 poly_info[poly_nr].edge_first;
148 if (ELEM(v_curr, eed->v1, eed->v2) == true && ELEM(v_prev, eed->v1, eed->v2) == false) {
149 return eed;
150 }
151
152 eed = (e_curr->prev && e_curr != poly_info[poly_nr].edge_first) ? e_curr->prev :
153 poly_info[poly_nr].edge_last;
154 if (ELEM(v_curr, eed->v1, eed->v2) == true && ELEM(v_prev, eed->v1, eed->v2) == false) {
155 return eed;
156 }
157
158 BLI_assert(0);
159 return NULL;
160}
161
163 PolyInfo *poly_info,
164 const ushort poly_nr,
165 ListBase *filledgebase)
166{
167 PolyInfo *pi = &poly_info[poly_nr];
168 GHash *isect_hash = NULL;
169 ListBase isect_lb = {NULL};
170
171 /* warning, O(n2) check here, should use spatial lookup */
172 {
173 ScanFillEdge *eed;
174
175 for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) {
176 ScanFillEdge *eed_other;
177
178 for (eed_other = eed->next; eed_other;
179 eed_other = (eed_other == pi->edge_last) ? NULL : eed_other->next)
180 {
181 if (!ELEM(eed->v1, eed_other->v1, eed_other->v2) &&
182 !ELEM(eed->v2, eed_other->v1, eed_other->v2) && (eed != eed_other))
183 {
184 /* check isect */
185 float pt[2];
186 BLI_assert(eed != eed_other);
187
189 eed->v1->co, eed->v2->co, eed_other->v1->co, eed_other->v2->co, pt) == 1)
190 {
191 ScanFillIsect *isect;
192
193 if (UNLIKELY(isect_hash == NULL)) {
194 isect_hash = BLI_ghash_ptr_new(__func__);
195 }
196
197 isect = MEM_mallocN(sizeof(ScanFillIsect), __func__);
198
199 BLI_addtail(&isect_lb, isect);
200
201 copy_v2_v2(isect->co, pt);
202 isect->co[2] = eed->v1->co[2];
203 isect->v = BLI_scanfill_vert_add(sf_ctx, isect->co);
204
205 /* NOTE: vert may belong to 2 polys now */
206 isect->v->poly_nr = eed->v1->poly_nr;
207
208 VFLAG_SET(isect->v, V_ISISECT);
209 edge_isect_ls_add(isect_hash, eed, isect);
210 edge_isect_ls_add(isect_hash, eed_other, isect);
211 }
212 }
213 }
214 }
215 }
216
217 if (isect_hash == NULL) {
218 return false;
219 }
220
221 /* now subdiv the edges */
222 {
223 ScanFillEdge *eed;
224
225 for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) {
226 if (eed->user_flag & E_ISISECT) {
227 ListBase *e_ls = BLI_ghash_lookup(isect_hash, eed);
228
229 LinkData *isect_link;
230
231 if (UNLIKELY(e_ls == NULL)) {
232 /* only happens in very rare cases (entirely overlapping splines).
233 * in this case we can't do much useful. but at least don't crash */
234 continue;
235 }
236
237 /* Maintain correct terminating edge. */
238 if (pi->edge_last == eed) {
239 pi->edge_last = NULL;
240 }
241
242 if (BLI_listbase_is_single(e_ls) == false) {
244 }
245
246 /* move original edge to filledgebase and add replacement
247 * (which gets subdivided next) */
248 {
249 ScanFillEdge *eed_tmp;
250 eed_tmp = BLI_scanfill_edge_add(sf_ctx, eed->v1, eed->v2);
251 BLI_remlink(&sf_ctx->filledgebase, eed_tmp);
252 BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_tmp);
253 BLI_remlink(&sf_ctx->filledgebase, eed);
254 BLI_addtail(filledgebase, eed);
255 if (pi->edge_first == eed) {
256 pi->edge_first = eed_tmp;
257 }
258 eed = eed_tmp;
259 }
260
261 for (isect_link = e_ls->first; isect_link; isect_link = isect_link->next) {
262 ScanFillIsect *isect = isect_link->data;
263 ScanFillEdge *eed_subd;
264
265 eed_subd = BLI_scanfill_edge_add(sf_ctx, isect->v, eed->v2);
266 eed_subd->poly_nr = poly_nr;
267 eed->v2 = isect->v;
268
269 BLI_remlink(&sf_ctx->filledgebase, eed_subd);
270 BLI_insertlinkafter(&sf_ctx->filledgebase, eed, eed_subd);
271
272 /* step to the next edge and continue dividing */
273 eed = eed_subd;
274 }
275
276 BLI_freelistN(e_ls);
277 MEM_freeN(e_ls);
278
279 if (pi->edge_last == NULL) {
280 pi->edge_last = eed;
281 }
282 }
283 }
284 }
285
286 BLI_freelistN(&isect_lb);
287 BLI_ghash_free(isect_hash, NULL, NULL);
288
289 {
290 ScanFillEdge *e_init;
291 ScanFillEdge *e_curr;
292 ScanFillEdge *e_next;
293
294 ScanFillVert *v_prev;
295 ScanFillVert *v_curr;
296
297 bool inside = false;
298
299 /* first vert */
300#if 0
301 e_init = pi->edge_last;
302 e_curr = e_init;
303 e_next = pi->edge_first;
304
305 v_prev = e_curr->v1;
306 v_curr = e_curr->v2;
307#else
308
309 /* find outside vertex */
310 {
311 ScanFillEdge *eed;
312 ScanFillEdge *eed_prev;
313 float min_x = FLT_MAX;
314
315 e_curr = pi->edge_last;
316 e_next = pi->edge_first;
317
318 eed_prev = pi->edge_last;
319 for (eed = pi->edge_first; eed; eed = (eed == pi->edge_last) ? NULL : eed->next) {
320 if (eed->v2->co[0] < min_x) {
321 min_x = eed->v2->co[0];
322 e_curr = eed_prev;
323 e_next = eed;
324 }
325 eed_prev = eed;
326 }
327
328 e_init = e_curr;
329 v_prev = e_curr->v1;
330 v_curr = e_curr->v2;
331 }
332#endif
333
334 BLI_assert(e_curr->poly_nr == poly_nr);
335 BLI_assert(pi->edge_last->poly_nr == poly_nr);
336
337 do {
338 ScanFillVert *v_next;
339
340 v_next = (e_next->v1 == v_curr) ? e_next->v2 : e_next->v1;
341 BLI_assert(ELEM(v_curr, e_next->v1, e_next->v2));
342
343 /* track intersections */
344 if (inside) {
345 EFLAG_SET(e_next, E_ISDELETE);
346 }
347 if (v_next->user_flag & V_ISISECT) {
348 inside = !inside;
349 }
350 /* now step... */
351
352 v_prev = v_curr;
353 v_curr = v_next;
354 e_curr = e_next;
355
356 e_next = edge_step(poly_info, poly_nr, v_prev, v_curr, e_curr);
357
358 } while (e_curr != e_init);
359 }
360
361 return true;
362}
363
365 ListBase *remvertbase,
366 ListBase *remedgebase)
367{
368 const uint poly_num = (uint)sf_ctx->poly_nr + 1;
369 uint eed_index = 0;
370 bool changed = false;
371
372 PolyInfo *poly_info;
373
374 if (UNLIKELY(sf_ctx->poly_nr == SF_POLY_UNSET)) {
375 return false;
376 }
377
378 poly_info = MEM_callocN(sizeof(*poly_info) * poly_num, __func__);
379
380 /* get the polygon span */
381 if (sf_ctx->poly_nr == 0) {
382 poly_info->edge_first = sf_ctx->filledgebase.first;
383 poly_info->edge_last = sf_ctx->filledgebase.last;
384 }
385 else {
386 ushort poly_nr;
387 ScanFillEdge *eed;
388
389 poly_nr = 0;
390
391 for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next, eed_index++) {
392
393 BLI_assert(eed->poly_nr == eed->v1->poly_nr);
394 BLI_assert(eed->poly_nr == eed->v2->poly_nr);
395
396 if ((poly_info[poly_nr].edge_last != NULL) &&
397 (poly_info[poly_nr].edge_last->poly_nr != eed->poly_nr))
398 {
399 poly_nr++;
400 }
401
402 if (poly_info[poly_nr].edge_first == NULL) {
403 poly_info[poly_nr].edge_first = eed;
404 poly_info[poly_nr].edge_last = eed;
405 }
406 else if (poly_info[poly_nr].edge_last->poly_nr == eed->poly_nr) {
407 poly_info[poly_nr].edge_last = eed;
408 }
409
410 BLI_assert(poly_info[poly_nr].edge_first->poly_nr == poly_info[poly_nr].edge_last->poly_nr);
411 }
412 }
413
414 /* self-intersect each polygon */
415 {
416 ushort poly_nr;
417 for (poly_nr = 0; poly_nr < poly_num; poly_nr++) {
418 changed |= scanfill_preprocess_self_isect(sf_ctx, poly_info, poly_nr, remedgebase);
419 }
420 }
421
422 MEM_freeN(poly_info);
423
424 if (changed == false) {
425 return false;
426 }
427
428 /* move free edges into their own list */
429 {
430 ScanFillEdge *eed;
431 ScanFillEdge *eed_next;
432 for (eed = sf_ctx->filledgebase.first; eed; eed = eed_next) {
433 eed_next = eed->next;
434 if (eed->user_flag & E_ISDELETE) {
435 BLI_remlink(&sf_ctx->filledgebase, eed);
436 BLI_addtail(remedgebase, eed);
437 }
438 }
439 }
440
441 /* move free vertices into their own list */
442 {
443 ScanFillEdge *eed;
444 ScanFillVert *eve;
445 ScanFillVert *eve_next;
446
447 for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
448 eve->user_flag = 0;
449 eve->poly_nr = SF_POLY_UNSET;
450 }
451 for (eed = sf_ctx->filledgebase.first; eed; eed = eed->next) {
452 eed->v1->user_flag = 1;
453 eed->v2->user_flag = 1;
454 eed->poly_nr = SF_POLY_UNSET;
455 }
456
457 for (eve = sf_ctx->fillvertbase.first; eve; eve = eve_next) {
458 eve_next = eve->next;
459 if (eve->user_flag != 1) {
460 BLI_remlink(&sf_ctx->fillvertbase, eve);
461 BLI_addtail(remvertbase, eve);
462 }
463 else {
464 eve->user_flag = 0;
465 }
466 }
467 }
468
469 /* polygon id's are no longer meaningful,
470 * when removing self intersections we may have created new isolated polys */
471 sf_ctx->poly_nr = SF_POLY_UNSET;
472
473#if 0
474 BLI_scanfill_view3d_dump(sf_ctx);
475 BLI_scanfill_obj_dump(sf_ctx);
476#endif
477
478 return changed;
479}
#define BLI_assert(a)
Definition BLI_assert.h:50
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:752
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:331
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
struct ScanFillVert * BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3])
Definition scanfill.c:95
struct ScanFillEdge * BLI_scanfill_edge_add(ScanFillContext *sf_ctx, struct ScanFillVert *v1, struct ScanFillVert *v2)
Definition scanfill.c:117
#define SF_POLY_UNSET
unsigned short ushort
unsigned int uint
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
Read Guarded memory(de)allocation.
local_group_size(16, 16) .push_constant(Type b
#define NULL
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define E_ISISECT
static ListBase * edge_isect_ls_add(GHash *isect_hash, ScanFillEdge *eed, ScanFillIsect *isect)
#define EFLAG_SET(eed, val)
#define VFLAG_SET(eve, val)
static int edge_isect_ls_sort_cb(void *thunk, const void *def_a_ptr, const void *def_b_ptr)
struct PolyInfo PolyInfo
static ScanFillEdge * edge_step(PolyInfo *poly_info, const ushort poly_nr, ScanFillVert *v_prev, ScanFillVert *v_curr, ScanFillEdge *e_curr)
#define E_ISDELETE
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx, ListBase *remvertbase, ListBase *remedgebase)
struct ScanFillIsect ScanFillIsect
#define V_ISISECT
static ListBase * edge_isect_ls_ensure(GHash *isect_hash, ScanFillEdge *eed)
static bool scanfill_preprocess_self_isect(ScanFillContext *sf_ctx, PolyInfo *poly_info, const ushort poly_nr, ListBase *filledgebase)
#define FLT_MAX
Definition stdcycles.h:14
void * data
struct LinkData * next
void * last
void * first
ScanFillEdge * edge_first
ScanFillEdge * edge_last
ScanFillVert * vert_outer
ListBase fillvertbase
ListBase filledgebase
unsigned short poly_nr
struct ScanFillEdge * prev
unsigned short poly_nr
struct ScanFillVert * v1
struct ScanFillVert * v2
struct ScanFillEdge * next
unsigned int user_flag
struct ScanFillIsect * next
struct ScanFillIsect * prev
ScanFillVert * v
unsigned short poly_nr
struct ScanFillVert * next
float co[3]
unsigned int user_flag
unsigned int keyindex