Blender V4.3
BLI_polyfill_2d_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7/* Use to write out OBJ files, handy for checking output */
8// #define USE_OBJ_PREVIEW
9
10/* test every possible offset and reverse */
11#define USE_COMBINATIONS_ALL
12#define USE_BEAUTIFY
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_array_utils.h"
17#include "BLI_map.hh"
18#include "BLI_math_geom.h"
19#include "BLI_ordered_edge.hh"
20#include "BLI_polyfill_2d.h"
21#include "BLI_utildefines.h"
22
23#ifdef USE_OBJ_PREVIEW
24# include "BLI_string.h"
25#endif
26
27#ifdef USE_BEAUTIFY
28# include "BLI_heap.h"
29# include "BLI_memarena.h"
31#endif
32
33static void polyfill_to_obj(const char *id,
34 const float poly[][2],
35 const uint poly_num,
36 const uint tris[][3],
37 const uint tris_num);
38
40 POLYFILL2D_TEST_IS_DEGENERATE = (1 << 0),
41 POLYFILL2D_TEST_NO_ZERO_AREA_TRIS = (1 << 1),
42 POLYFILL2D_TEST_NOP = 0,
43};
44
45/* -------------------------------------------------------------------- */
46/* test utility functions */
47
48#define TRI_ERROR_VALUE uint(-1)
49
50static void test_valid_polyfill_prepare(uint tris[][3], uint tris_num)
51{
52 uint i;
53 for (i = 0; i < tris_num; i++) {
54 uint j;
55 for (j = 0; j < 3; j++) {
56 tris[i][j] = TRI_ERROR_VALUE;
57 }
58 }
59}
60
68static void test_polyfill_simple(const float /*poly*/[][2],
69 const uint poly_num,
70 const uint tris[][3],
71 const uint tris_num)
72{
73 uint i;
74 int *used_num = (int *)MEM_callocN(poly_num * sizeof(int), __func__);
75 for (i = 0; i < tris_num; i++) {
76 uint j;
77 for (j = 0; j < 3; j++) {
78 EXPECT_NE(TRI_ERROR_VALUE, tris[i][j]);
79 used_num[tris[i][j]] += 1;
80 }
81 EXPECT_NE(tris[i][0], tris[i][1]);
82 EXPECT_NE(tris[i][1], tris[i][2]);
83 EXPECT_NE(tris[i][2], tris[i][0]);
84 }
85 for (i = 0; i < poly_num; i++) {
86 EXPECT_NE(0, used_num[i]);
87 }
88 MEM_freeN(used_num);
89}
90
91static void test_polyfill_topology(const float /*poly*/[][2],
92 const uint poly_num,
93 const uint tris[][3],
94 const uint tris_num)
95{
97 uint i;
98 for (i = 0; i < tris_num; i++) {
99 uint j;
100 for (j = 0; j < 3; j++) {
101 const uint v1 = tris[i][j];
102 const uint v2 = tris[i][(j + 1) % 3];
103 edgehash.add_or_modify(
104 {v1, v2}, [](int *value) { *value = 1; }, [](int *value) { (*value)++; });
105 }
106 }
107 EXPECT_EQ(edgehash.size(), poly_num + (poly_num - 3));
108
109 for (i = 0; i < poly_num; i++) {
110 const uint v1 = i;
111 const uint v2 = (i + 1) % poly_num;
112 EXPECT_TRUE(edgehash.contains({v1, v2}));
113 EXPECT_EQ(edgehash.lookup({v1, v2}), 1);
114 }
115
116 for (const int value : edgehash.values()) {
117 EXPECT_TRUE(ELEM(value, 1, 2));
118 }
119}
120
124static void test_polyfill_winding(const float poly[][2],
125 const uint /*poly_num*/,
126 const uint tris[][3],
127 const uint tris_num)
128{
129 uint i;
130 uint count[2] = {0, 0};
131 for (i = 0; i < tris_num; i++) {
132 float winding_test = cross_tri_v2(poly[tris[i][0]], poly[tris[i][1]], poly[tris[i][2]]);
133 if (fabsf(winding_test) > FLT_EPSILON) {
134 count[winding_test < 0.0f] += 1;
135 }
136 }
137 EXPECT_TRUE(ELEM(0, count[0], count[1]));
138}
139
143static void test_polyfill_area(const float poly[][2],
144 const uint poly_num,
145 const uint tris[][3],
146 const uint tris_num)
147{
148 uint i;
149 const float area_total = area_poly_v2(poly, poly_num);
150 float area_total_tris = 0.0f;
151 const float eps_abs = 0.00001f;
152 const float eps = area_total > 1.0f ? (area_total * eps_abs) : eps_abs;
153 for (i = 0; i < tris_num; i++) {
154 area_total_tris += area_tri_v2(poly[tris[i][0]], poly[tris[i][1]], poly[tris[i][2]]);
155 }
156 EXPECT_NEAR(area_total, area_total_tris, eps);
157}
158
162static void test_polyfill_area_tri_nonzero(const float poly[][2],
163 const uint /*poly_num*/,
164 const uint tris[][3],
165 const uint tris_num)
166{
167 uint i;
168 uint total = 0;
169 for (i = 0; i < tris_num; i++) {
170 if (area_tri_v2(poly[tris[i][0]], poly[tris[i][1]], poly[tris[i][2]]) < 1e-6f) {
171 total += 1;
172 }
173 }
174 EXPECT_EQ(total, 0);
175}
176
177/* -------------------------------------------------------------------- */
178/* Macro and helpers to manage checking */
182static void test_polyfill_template_check(const char *id,
183 const ePolyFill2DTestFlag test_flag,
184 const float poly[][2],
185 const uint poly_num,
186 const uint tris[][3],
187 const uint tris_num)
188{
189 test_polyfill_simple(poly, poly_num, tris, tris_num);
190 test_polyfill_topology(poly, poly_num, tris, tris_num);
191 if (!(test_flag & POLYFILL2D_TEST_IS_DEGENERATE)) {
192 test_polyfill_winding(poly, poly_num, tris, tris_num);
193
194 test_polyfill_area(poly, poly_num, tris, tris_num);
195
196 /* Only check when non-degenerate, because the number of zero area triangles
197 * are undefined for degenerate polygons as there is no correct solution. */
198 if (test_flag & POLYFILL2D_TEST_NO_ZERO_AREA_TRIS) {
199 test_polyfill_area_tri_nonzero(poly, poly_num, tris, tris_num);
200 }
201 }
202 polyfill_to_obj(id, poly, poly_num, tris, tris_num);
203}
204
205static void test_polyfill_template(const char *id,
206 const ePolyFill2DTestFlag test_flag,
207 const float poly[][2],
208 const uint poly_num,
209 uint tris[][3],
210 const uint tris_num)
211{
212 test_valid_polyfill_prepare(tris, tris_num);
213 BLI_polyfill_calc(poly, poly_num, 0, tris);
214
215 /* check all went well */
216 test_polyfill_template_check(id, test_flag, poly, poly_num, tris, tris_num);
217
218#ifdef USE_BEAUTIFY
219 /* check beautify gives good results too */
220 {
223
224 BLI_polyfill_beautify(poly, poly_num, tris, pf_arena, pf_heap);
225
226 test_polyfill_template_check(id, test_flag, poly, poly_num, tris, tris_num);
227
228 BLI_memarena_free(pf_arena);
229 BLI_heap_free(pf_heap, nullptr);
230 }
231#endif
232}
233
234static void test_polyfill_template_flip_sign(const char *id,
235 const ePolyFill2DTestFlag test_flag,
236 const float poly[][2],
237 const uint poly_num,
238 uint tris[][3],
239 const uint tris_num)
240{
241 float(*poly_copy)[2] = (float(*)[2])MEM_mallocN(sizeof(float[2]) * poly_num, id);
242 for (int flip_x = 0; flip_x < 2; flip_x++) {
243 for (int flip_y = 0; flip_y < 2; flip_y++) {
244 float sign_x = flip_x ? -1.0f : 1.0f;
245 float sign_y = flip_y ? -1.0f : 1.0f;
246 for (int i = 0; i < poly_num; i++) {
247 poly_copy[i][0] = poly[i][0] * sign_x;
248 poly_copy[i][1] = poly[i][1] * sign_y;
249 }
250 test_polyfill_template(id, test_flag, poly_copy, poly_num, tris, tris_num);
251 }
252 }
253 MEM_freeN(poly_copy);
254}
255
256#ifdef USE_COMBINATIONS_ALL
257static void test_polyfill_template_main(const char *id,
258 const ePolyFill2DTestFlag test_flag,
259 const float poly[][2],
260 const uint poly_num,
261 uint tris[][3],
262 const uint tris_num)
263{
264 /* overkill? - try at _every_ offset & reverse */
265 uint poly_reverse;
266 float(*poly_copy)[2] = (float(*)[2])MEM_mallocN(sizeof(float[2]) * poly_num, id);
267 float tmp[2];
268
269 memcpy(poly_copy, poly, sizeof(float[2]) * poly_num);
270
271 for (poly_reverse = 0; poly_reverse < 2; poly_reverse++) {
272 uint poly_cycle;
273
274 if (poly_reverse) {
275 BLI_array_reverse(poly_copy, poly_num);
276 }
277
278 for (poly_cycle = 0; poly_cycle < poly_num; poly_cycle++) {
279 // printf("polytest %s ofs=%d, reverse=%d\n", id, poly_cycle, poly_reverse);
280 test_polyfill_template_flip_sign(id, test_flag, poly, poly_num, tris, tris_num);
281
282 /* cycle */
283 copy_v2_v2(tmp, poly_copy[0]);
284 memmove(&poly_copy[0], &poly_copy[1], (poly_num - 1) * sizeof(float[2]));
285 copy_v2_v2(poly_copy[poly_num - 1], tmp);
286 }
287 }
288
289 MEM_freeN(poly_copy);
290}
291#else /* USE_COMBINATIONS_ALL */
292static void test_polyfill_template_main(const char *id,
293 const ePolyFill2DTestFlag test_flag,
294 const float poly[][2],
295 const uint poly_num,
296 uint tris[][3],
297 const uint tris_num)
298{
299 test_polyfill_template_flip_sign(id, test_flag, poly, poly_num, tris, tris_num);
300}
301#endif /* USE_COMBINATIONS_ALL */
302
303#define TEST_POLYFILL_TEMPLATE_STATIC(poly, test_flag) \
304 { \
305 uint tris[POLY_TRI_COUNT(ARRAY_SIZE(poly))][3]; \
306 const uint poly_num = ARRAY_SIZE(poly); \
307 const uint tris_num = ARRAY_SIZE(tris); \
308 const char *id = typeid(*this).name(); \
309\
310 test_polyfill_template_main(id, test_flag, poly, poly_num, tris, tris_num); \
311 } \
312 (void)0
313
314/* -------------------------------------------------------------------- */
315/* visualization functions (not needed for testing) */
316
317#ifdef USE_OBJ_PREVIEW
318static void polyfill_to_obj(const char *id,
319 const float poly[][2],
320 const uint poly_num,
321 const uint tris[][3],
322 const uint tris_num)
323{
324 char path[1024];
325 FILE *f;
326 uint i;
327
328 SNPRINTF(path, "%s.obj", id);
329
330 f = fopen(path, "w");
331 if (!f) {
332 return;
333 }
334
335 for (i = 0; i < poly_num; i++) {
336 fprintf(f, "v %f %f 0.0\n", UNPACK2(poly[i]));
337 }
338
339 for (i = 0; i < tris_num; i++) {
340 fprintf(f, "f %u %u %u\n", UNPACK3_EX(1 +, tris[i], ));
341 }
342
343 fclose(f);
344}
345#else
346static void polyfill_to_obj(const char *id,
347 const float poly[][2],
348 const uint poly_num,
349 const uint tris[][3],
350 const uint tris_num)
351{
352 (void)id;
353 (void)poly, (void)poly_num;
354 (void)tris, (void)tris_num;
355}
356#endif /* USE_OBJ_PREVIEW */
357
358/* -------------------------------------------------------------------- */
359/* tests */
360
398#define POLY_TRI_COUNT(len) ((len)-2)
399
400/* A counterclockwise triangle */
401TEST(polyfill2d, TriangleCCW)
402{
403 const float poly[][2] = {{0, 0}, {0, 1}, {1, 0}};
404 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
405}
406
407/* A counterclockwise square */
408TEST(polyfill2d, SquareCCW)
409{
410 const float poly[][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
411 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
412}
413
414/* A clockwise square */
415TEST(polyfill2d, SquareCW)
416{
417 const float poly[][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
418 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
419}
420
421/* Star-fleet insignia. */
422TEST(polyfill2d, Starfleet)
423{
424 const float poly[][2] = {{0, 0}, {0.6f, 0.4f}, {1, 0}, {0.5f, 1}};
425 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
426}
427
428/* Star-fleet insignia with repeated point. */
429TEST(polyfill2d, StarfleetDegenerate)
430{
431 const float poly[][2] = {{0, 0}, {0.6f, 0.4f}, {0.6f, 0.4f}, {1, 0}, {0.5f, 1}};
432 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
433}
434
435/* Three collinear points */
436TEST(polyfill2d, 3Colinear)
437{
438 const float poly[][2] = {{0, 0}, {1, 0}, {2, 0}};
439 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
440}
441
442/* Four collinear points */
443TEST(polyfill2d, 4Colinear)
444{
445 const float poly[][2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
446 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
447}
448
449/* Non-consecutive collinear points */
450TEST(polyfill2d, UnorderedColinear)
451{
452 const float poly[][2] = {{0, 0}, {1, 1}, {2, 0}, {3, 1}, {4, 0}};
453 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
454}
455
456/* Plus shape */
457TEST(polyfill2d, PlusShape)
458{
459 const float poly[][2] = {
460 {1, 0},
461 {2, 0},
462 {2, 1},
463 {3, 1},
464 {3, 2},
465 {2, 2},
466 {2, 3},
467 {1, 3},
468 {1, 2},
469 {0, 2},
470 {0, 1},
471 {1, 1},
472 };
473 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
474}
475
476/* Star shape */
477TEST(polyfill2d, StarShape)
478{
479 const float poly[][2] = {{4, 0}, {5, 3}, {8, 4}, {5, 5}, {4, 8}, {3, 5}, {0, 4}, {3, 3}};
480 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
481}
482
483/* U shape */
484TEST(polyfill2d, UShape)
485{
486 const float poly[][2] = {
487 {1, 0}, {2, 0}, {3, 1}, {3, 3}, {2, 3}, {2, 1}, {1, 1}, {1, 3}, {0, 3}, {0, 1}};
488 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
489}
490
491/* Spiral */
492TEST(polyfill2d, Spiral)
493{
494 const float poly[][2] = {
495 {1, 0},
496 {4, 0},
497 {5, 1},
498 {5, 4},
499 {4, 5},
500 {1, 5},
501 {0, 4},
502 {0, 3},
503 {1, 2},
504 {2, 2},
505 {3, 3},
506 {1, 3},
507 {1, 4},
508 {4, 4},
509 {4, 1},
510 {0, 1},
511 };
512 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
513}
514
515/* Test case from http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml */
516TEST(polyfill2d, TestFlipCode)
517{
518 const float poly[][2] = {
519 {0, 6},
520 {0, 0},
521 {3, 0},
522 {4, 1},
523 {6, 1},
524 {8, 0},
525 {12, 0},
526 {13, 2},
527 {8, 2},
528 {8, 4},
529 {11, 4},
530 {11, 6},
531 {6, 6},
532 {4, 3},
533 {2, 6},
534 };
535 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
536}
537
538/* Self-intersection */
539TEST(polyfill2d, SelfIntersect)
540{
541 const float poly[][2] = {{0, 0}, {1, 1}, {2, -1}, {3, 1}, {4, 0}};
542 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_IS_DEGENERATE);
543}
544
545/* Self-touching */
546TEST(polyfill2d, SelfTouch)
547{
548 const float poly[][2] = {
549 {0, 0},
550 {4, 0},
551 {4, 4},
552 {2, 4},
553 {2, 3},
554 {3, 3},
555 {3, 1},
556 {1, 1},
557 {1, 3},
558 {2, 3},
559 {2, 4},
560 {0, 4},
561 };
562 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
563}
564
565/* Self-overlapping */
566TEST(polyfill2d, SelfOverlap)
567{
568 const float poly[][2] = {
569 {0, 0},
570 {4, 0},
571 {4, 4},
572 {1, 4},
573 {1, 3},
574 {3, 3},
575 {3, 1},
576 {1, 1},
577 {1, 3},
578 {3, 3},
579 {3, 4},
580 {0, 4},
581 };
582 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_IS_DEGENERATE);
583}
584
585/* Test case from http://www.davdata.nl/math/polygons.html */
586TEST(polyfill2d, TestDavData)
587{
588 const float poly[][2] = {
589 {190, 480}, {140, 180}, {310, 100}, {330, 390}, {290, 390}, {280, 260}, {220, 260},
590 {220, 430}, {370, 430}, {350, 30}, {50, 30}, {160, 560}, {730, 510}, {710, 20},
591 {410, 30}, {470, 440}, {640, 410}, {630, 140}, {590, 140}, {580, 360}, {510, 370},
592 {510, 60}, {650, 70}, {660, 450}, {190, 480},
593 };
594 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
595}
596
597/* Issue 815, http://code.google.com/p/libgdx/issues/detail?id=815 */
598TEST(polyfill2d, Issue815)
599{
600 const float poly[][2] = {
601 {-2.0f, 0.0f},
602 {-2.0f, 0.5f},
603 {0.0f, 1.0f},
604 {0.5f, 2.875f},
605 {1.0f, 0.5f},
606 {1.5f, 1.0f},
607 {2.0f, 1.0f},
608 {2.0f, 0.0f},
609 };
610 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
611}
612
613/* Issue 207, comment #1, http://code.google.com/p/libgdx/issues/detail?id=207#c1 */
614TEST(polyfill2d, Issue207_1)
615{
616 const float poly[][2] = {
617 {72.42465f, 197.07095f},
618 {78.485535f, 189.92776f},
619 {86.12059f, 180.92929f},
620 {99.68253f, 164.94557f},
621 {105.24325f, 165.79604f},
622 {107.21862f, 166.09814f},
623 {112.41958f, 162.78253f},
624 {113.73238f, 161.94562f},
625 {123.29477f, 167.93805f},
626 {126.70667f, 170.07617f},
627 {73.22717f, 199.51062f},
628 };
629 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_IS_DEGENERATE);
630}
631
632/* Issue 207, comment #11, http://code.google.com/p/libgdx/issues/detail?id=207#c11 */
633/* Also on issue 1081, http://code.google.com/p/libgdx/issues/detail?id=1081 */
634TEST(polyfill2d, Issue207_11)
635{
636 const float poly[][2] = {
637 {2400.0f, 480.0f}, {2400.0f, 176.0f}, {1920.0f, 480.0f},
638 {1920.0459f, 484.22314f}, {1920.1797f, 487.91016f}, {1920.3955f, 491.0874f},
639 {1920.6875f, 493.78125f}, {1921.0498f, 496.01807f}, {1921.4766f, 497.82422f},
640 {1921.9619f, 499.22607f}, {1922.5f, 500.25f}, {1923.085f, 500.92236f},
641 {1923.7109f, 501.26953f}, {1924.3721f, 501.31787f}, {1925.0625f, 501.09375f},
642 {1925.7764f, 500.62354f}, {1926.5078f, 499.9336f}, {1927.251f, 499.0503f},
643 {1928.0f, 498.0f}, {1928.749f, 496.80908f}, {1929.4922f, 495.5039f},
644 {1930.2236f, 494.11084f}, {1930.9375f, 492.65625f}, {1931.6279f, 491.1665f},
645 {1932.2891f, 489.66797f}, {1932.915f, 488.187f}, {1933.5f, 486.75f},
646 {1934.0381f, 485.3833f}, {1934.5234f, 484.11328f}, {1934.9502f, 482.9663f},
647 {1935.3125f, 481.96875f}, {1935.6045f, 481.14697f}, {1935.8203f, 480.52734f},
648 {1935.9541f, 480.13623f}, {1936.0f, 480.0f}};
649 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
650}
651
652/* Issue 1407, http://code.google.com/p/libgdx/issues/detail?id=1407 */
653TEST(polyfill2d, Issue1407)
654{
655 const float poly[][2] = {
656 {3.914329f, 1.9008259f},
657 {4.414321f, 1.903619f},
658 {4.8973203f, 1.9063174f},
659 {5.4979978f, 1.9096732f},
660 };
661 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
662}
663
664/* Issue 1407, http://code.google.com/p/libgdx/issues/detail?id=1407, */
665/* with an additional point to show what is happening. */
666TEST(polyfill2d, Issue1407_pt)
667{
668 const float poly[][2] = {
669 {3.914329f, 1.9008259f},
670 {4.414321f, 1.903619f},
671 {4.8973203f, 1.9063174f},
672 {5.4979978f, 1.9096732f},
673 {4, 4},
674 };
675 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
676}
677
678/* Simplified from Blender bug #40777 */
679TEST(polyfill2d, IssueT40777_colinear)
680{
681 const float poly[][2] = {
682 {0.7, 0.37}, {0.7, 0}, {0.76, 0}, {0.76, 0.4}, {0.83, 0.4}, {0.83, 0}, {0.88, 0},
683 {0.88, 0.4}, {0.94, 0.4}, {0.94, 0}, {1, 0}, {1, 0.4}, {0.03, 0.62}, {0.03, 0.89},
684 {0.59, 0.89}, {0.03, 1}, {0, 1}, {0, 0}, {0.03, 0}, {0.03, 0.37},
685 };
686 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
687}
688
689/* Blender bug #41986 */
690TEST(polyfill2d, IssueT41986_axis_align)
691{
692 const float poly[][2] = {
693 {-0.25, -0.07}, {-0.25, 0.27}, {-1.19, 0.14}, {-0.06, 0.73}, {0.17, 1.25},
694 {-0.25, 1.07}, {-0.38, 1.02}, {-0.25, 0.94}, {-0.40, 0.90}, {-0.41, 0.86},
695 {-0.34, 0.83}, {-0.25, 0.82}, {-0.66, 0.73}, {-0.56, 1.09}, {-0.25, 1.10},
696 {0.00, 1.31}, {-0.03, 1.47}, {-0.25, 1.53}, {0.12, 1.62}, {0.36, 1.07},
697 {0.12, 0.67}, {0.29, 0.57}, {0.44, 0.45}, {0.57, 0.29}, {0.66, 0.12},
698 {0.68, 0.06}, {0.57, -0.36}, {-0.25, -0.37}, {0.49, -0.74}, {-0.59, -1.21},
699 {-0.25, -0.15}, {-0.46, -0.52}, {-1.08, -0.83}, {-1.45, -0.33}, {-1.25, -0.04}};
700
701 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
702}
703
704/* Blender bug #52834 */
705TEST(polyfill2d, IssueT52834_axis_align_co_linear)
706{
707 const float poly[][2] = {
708 {40, 0}, {36, 0}, {36, 5}, {35, 5}, {35, 0}, {30, 0}, {30, 5}, {29, 5},
709 {29, 0}, {24, 0}, {24, 3}, {23, 4}, {23, 0}, {18, 0}, {18, 5}, {17, 5},
710 {17, 0}, {12, 0}, {12, 5}, {11, 5}, {11, 0}, {6, 0}, {6, 5}, {5, 5},
711 {5, 0}, {0, 0}, {0, 5}, {-1, 5}, {-1, 0}, {-6, 0}, {-9, -3}, {-6, -3},
712 {-6, -2}, {-1, -2}, {0, -2}, {5, -2}, {6, -2}, {11, -2}, {12, -2}, {17, -2},
713 {18, -2}, {23, -2}, {24, -2}, {29, -2}, {30, -2}, {35, -2}, {36, -2}, {40, -2},
714 };
715
716 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
717}
718
719/* Blender bug #67109 (version a). */
720/* Multiple versions are offset & rotated, this fails in cases where others works. */
721TEST(polyfill2d, IssueT67109_axis_align_co_linear_a)
722{
723 const float poly[][2] = {
724 {3.2060661, -11.438997},
725 {2.8720665, -5.796999},
726 {-2.8659325, -5.796999},
727 {-2.8659325, -8.307999},
728 {-3.2549324, -11.438997},
729 {-2.8659325, -5.4869995},
730 {2.8720665, -5.4869995},
731 {2.8720665, -2.9759989},
732 {2.8720665, -2.6659985},
733 {2.8720665, -0.15499878},
734 };
735 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
736}
737
738/* Blender bug #67109, (version b). */
739TEST(polyfill2d, IssueT67109_axis_align_co_linear_b)
740{
741 const float poly[][2] = {
742 {32.41416, -12.122593},
743 {28.094929, -8.477332},
744 {24.141455, -12.636018},
745 {25.96133, -14.366093},
746 {27.96254, -16.805279},
747 {23.916779, -12.422427},
748 {27.870255, -8.263744},
749 {26.050375, -6.533667},
750 {25.825695, -6.320076},
751 {24.00582, -4.5899982},
752 };
753 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
754}
755
756/* Blender bug #67109 (version c). */
757TEST(polyfill2d, IssueT67109_axis_align_co_linear_c)
758{
759 const float poly[][2] = {
760 {-67.10034, 43.677097},
761 {-63.253956, 61.399143},
762 {-80.98382, 66.36057},
763 {-83.15499, 58.601795},
764 {-87.06422, 49.263668},
765 {-80.71576, 67.31843},
766 {-62.985912, 62.35701},
767 {-60.81475, 70.11576},
768 {-60.546703, 71.07365},
769 {-58.37554, 78.83239},
770 };
771 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NOP);
772}
773
774/* Blender bug #103913 where co-linear edges create zero area tessellation
775 * when a valid solution exists without zero area triangles. */
776TEST(polyfill2d, Issue103913_axis_align_co_linear_no_zero_area_tri)
777{
778 const float poly[][2] = {
779 {-10, 0}, {-10, 2}, {-8, 2}, {-6, 2}, {-4, 2}, {-2, 2}, {-2, 4}, {-2, 6},
780 {-2, 8}, {-2, 10}, {0, 10}, {2, 10}, {2, 8}, {2, 6}, {2, 4}, {2, 2},
781 {4, 2}, {6, 2}, {8, 2}, {10, 2}, {10, 0}, {10, -2}, {8, -2}, {6, -2},
782 {4, -2}, {2, -2}, {2, -4}, {2, -6}, {2, -8}, {2, -10}, {0, -10}, {-2, -10},
783 {-2, -8}, {-2, -6}, {-2, -4}, {-2, -2}, {-4, -2}, {-6, -2}, {-8, -2}, {-10, -2},
784 };
785 TEST_POLYFILL_TEMPLATE_STATIC(poly, POLYFILL2D_TEST_NO_ZERO_AREA_TRIS);
786}
Generic array manipulation API.
#define BLI_array_reverse(arr, arr_len)
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
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
MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2])
float area_poly_v2(const float verts[][2], unsigned int nr)
Definition math_geom.cc:180
MINLINE void copy_v2_v2(float r[2], const float a[2])
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
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_polyfill_beautify(const float(*coords)[2], unsigned int coords_num, unsigned int(*tris)[3], struct MemArena *arena, struct Heap *eheap)
static void test_polyfill_template(const char *id, const ePolyFill2DTestFlag test_flag, const float poly[][2], const uint poly_num, uint tris[][3], const uint tris_num)
#define TRI_ERROR_VALUE
static void test_polyfill_template_main(const char *id, const ePolyFill2DTestFlag test_flag, const float poly[][2], const uint poly_num, uint tris[][3], const uint tris_num)
static void polyfill_to_obj(const char *id, const float poly[][2], const uint poly_num, const uint tris[][3], const uint tris_num)
static void test_valid_polyfill_prepare(uint tris[][3], uint tris_num)
#define TEST_POLYFILL_TEMPLATE_STATIC(poly, test_flag)
TEST(polyfill2d, TriangleCCW)
static void test_polyfill_area_tri_nonzero(const float poly[][2], const uint, const uint tris[][3], const uint tris_num)
static void test_polyfill_template_check(const char *id, const ePolyFill2DTestFlag test_flag, const float poly[][2], const uint poly_num, const uint tris[][3], const uint tris_num)
static void test_polyfill_topology(const float[][2], const uint poly_num, const uint tris[][3], const uint tris_num)
static void test_polyfill_simple(const float[][2], const uint poly_num, const uint tris[][3], const uint tris_num)
static void test_polyfill_template_flip_sign(const char *id, const ePolyFill2DTestFlag test_flag, const float poly[][2], const uint poly_num, uint tris[][3], const uint tris_num)
enum ePolyFill2DTestFlag { POLYFILL2D_TEST_IS_DEGENERATE=(1<< 0), POLYFILL2D_TEST_NO_ZERO_AREA_TRIS=(1<< 1), POLYFILL2D_TEST_NOP=0, } ePolyFill2DTestFlag
static void test_polyfill_winding(const float poly[][2], const uint, const uint tris[][3], const uint tris_num)
static void test_polyfill_area(const float poly[][2], const uint poly_num, const uint tris[][3], const uint tris_num)
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
#define UNPACK2(a)
#define UNPACK3_EX(pre, a, post)
#define ELEM(...)
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
ValueIterator values() const
Definition BLI_map.hh:846
int64_t size() const
Definition BLI_map.hh:927
bool contains(const Key &key) const
Definition BLI_map.hh:329
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:457
#define fabsf(x)
draw_view in_light_buf[] float
int count
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
const btScalar eps
Definition poly34.cpp:11