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