KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_poly_triangulation.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 */
11
15#include <trigo.h>
16#include <thread>
17#include <chrono>
18#include <future>
19
21#include <qa_utils/numeric.h>
23
24#include "geom_test_utils.h"
25
26BOOST_AUTO_TEST_SUITE( PolygonTriangulation )
27
28// Helper class to properly manage TRIANGULATED_POLYGON lifecycle
30{
31public:
32 TRIANGULATION_TEST_FIXTURE() : m_result( std::make_unique<SHAPE_POLY_SET::TRIANGULATED_POLYGON>(0) )
33 {
34 }
35
37
38 std::unique_ptr<POLYGON_TRIANGULATION> CreateTriangulator()
39 {
40 return std::make_unique<POLYGON_TRIANGULATION>( *m_result );
41 }
42
43private:
44 std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON> m_result;
45};
46
47// Helper function to create a simple square
48SHAPE_LINE_CHAIN createSquare( int size = 100, VECTOR2I offset = VECTOR2I(0, 0) )
49{
51 chain.Append( offset.x, offset.y );
52 chain.Append( offset.x + size, offset.y );
53 chain.Append( offset.x + size, offset.y + size );
54 chain.Append( offset.x, offset.y + size );
55 chain.SetClosed( true );
56 return chain;
57}
58
59// Helper function to create a triangle
60SHAPE_LINE_CHAIN createTriangle( int size = 100, VECTOR2I offset = VECTOR2I(0, 0) )
61{
63 chain.Append( offset.x, offset.y );
64 chain.Append( offset.x + size, offset.y );
65 chain.Append( offset.x + size/2, offset.y + size );
66 chain.SetClosed( true );
67 return chain;
68}
69
70// Helper function to create a complex concave polygon
72{
74 chain.Append( 0, 0 );
75 chain.Append( size, 0 );
76 chain.Append( size, size/2 );
77 chain.Append( size/2, size/2 ); // Create concave section
78 chain.Append( size/2, size );
79 chain.Append( 0, size );
80 chain.SetClosed( true );
81 return chain;
82}
83
84// Helper function to validate triangulation result with comprehensive checks
86 const SHAPE_LINE_CHAIN& original, bool strict = true )
87{
88 // Basic validation
89 if( result.GetVertexCount() == 0 )
90 return false;
91
92 size_t triangleCount = result.GetTriangleCount();
93 if( triangleCount == 0 )
94 return false;
95
96 // Validate triangle topology
97 for( size_t i = 0; i < triangleCount; i++ )
98 {
99 const auto& triangle = result.Triangles()[i];
100
101 // Check valid vertex indices
102 if( triangle.a >= (int)result.GetVertexCount() ||
103 triangle.b >= (int)result.GetVertexCount() ||
104 triangle.c >= (int)result.GetVertexCount() )
105 {
106 return false;
107 }
108
109 // Triangle vertices should not be the same
110 if( triangle.a == triangle.b || triangle.b == triangle.c || triangle.a == triangle.c )
111 return false;
112
113 // Check triangle area is positive (counter-clockwise orientation)
114 if( strict && triangle.Area() <= 0 )
115 return false;
116 }
117
118 // Validate that original vertices are preserved
119 if( strict && result.GetVertexCount() >= original.PointCount() )
120 {
121 const auto& vertices = result.Vertices();
122 for( int i = 0; i < original.PointCount(); i++ )
123 {
124 bool found = false;
125 for( size_t j = 0; j < vertices.size(); j++ )
126 {
127 if( vertices[j] == original.CPoint( i ) )
128 {
129 found = true;
130 break;
131 }
132 }
133 if( !found )
134 return false;
135 }
136 }
137
138 return true;
139}
140
141// Core functionality tests
142BOOST_AUTO_TEST_CASE( BasicTriangleTriangulation )
143{
145 auto triangulator = fixture.CreateTriangulator();
146
147 SHAPE_LINE_CHAIN triangle = createTriangle();
148
149 bool success = triangulator->TesselatePolygon( triangle, nullptr );
150
151 BOOST_TEST( success );
152 BOOST_TEST( fixture.GetResult().GetVertexCount() == 3 );
153 BOOST_TEST( fixture.GetResult().GetTriangleCount() == 1 );
154 BOOST_TEST( validateTriangulation( fixture.GetResult(), triangle ) );
155}
156
157BOOST_AUTO_TEST_CASE( BasicSquareTriangulation )
158{
160 auto triangulator = fixture.CreateTriangulator();
161
163
164 bool success = triangulator->TesselatePolygon( square, nullptr );
165
166 BOOST_TEST( success );
167 BOOST_TEST( fixture.GetResult().GetVertexCount() == 4 );
168 BOOST_TEST( fixture.GetResult().GetTriangleCount() == 2 );
170}
171
172BOOST_AUTO_TEST_CASE( ConcavePolygonTriangulation )
173{
175 auto triangulator = fixture.CreateTriangulator();
176
177 SHAPE_LINE_CHAIN concave = createConcavePolygon(100000);
178
179 bool success = triangulator->TesselatePolygon( concave, nullptr );
180
181 BOOST_TEST( success );
182
183 const auto& result = fixture.GetResult();
184 bool isValid = validateTriangulation( result, concave );
185 size_t triangleCount = result.GetTriangleCount();
186
187 // Print diagnostic information if validation fails or triangle count is unexpected
188 if( !success || !isValid || triangleCount < 4 )
189 {
190 std::cout << "\n=== ConcavePolygonTriangulation Diagnostic Output ===" << std::endl;
191 std::cout << "Success: " << (success ? "true" : "false") << std::endl;
192 std::cout << "Validation: " << (isValid ? "true" : "false") << std::endl;
193 std::cout << "Triangle count: " << triangleCount << " (expected >= 4)" << std::endl;
194 std::cout << "Vertex count: " << result.GetVertexCount() << std::endl;
195
196 // Print input polygon vertices
197 std::cout << "\nInput polygon vertices (" << concave.PointCount() << " points):" << std::endl;
198 for( int i = 0; i < concave.PointCount(); i++ )
199 {
200 VECTOR2I pt = concave.CPoint( i );
201 std::cout << " [" << i << "]: (" << pt.x << ", " << pt.y << ")" << std::endl;
202 }
203
204 // Print result vertices
205 std::cout << "\nResult vertices (" << result.GetVertexCount() << " points):" << std::endl;
206 const auto& vertices = result.Vertices();
207 for( size_t i = 0; i < vertices.size(); i++ )
208 {
209 std::cout << " [" << i << "]: (" << vertices[i].x << ", " << vertices[i].y << ")" << std::endl;
210 }
211
212 // Print triangles
213 std::cout << "\nTriangles found (" << triangleCount << " triangles):" << std::endl;
214 const auto& triangles = result.Triangles();
215 for( size_t i = 0; i < triangles.size(); i++ )
216 {
217 const auto& tri = triangles[i];
218 VECTOR2I va = vertices[tri.a];
219 VECTOR2I vb = vertices[tri.b];
220 VECTOR2I vc = vertices[tri.c];
221 double area = tri.Area();
222
223 std::cout << " Triangle[" << i << "]: indices(" << tri.a << "," << tri.b << "," << tri.c << ")" << std::endl;
224 std::cout << " A: (" << va.x << ", " << va.y << ")" << std::endl;
225 std::cout << " B: (" << vb.x << ", " << vb.y << ")" << std::endl;
226 std::cout << " C: (" << vc.x << ", " << vc.y << ")" << std::endl;
227 std::cout << " Area: " << area << std::endl;
228
229 // Check for degenerate triangles
230 if( area <= 0 )
231 std::cout << " *** DEGENERATE TRIANGLE (area <= 0) ***" << std::endl;
232 if( tri.a == tri.b || tri.b == tri.c || tri.a == tri.c )
233 std::cout << " *** INVALID TRIANGLE (duplicate vertex indices) ***" << std::endl;
234 }
235
236 // Additional diagnostic information
237 if( triangleCount > 0 )
238 {
239 double totalArea = 0.0;
240 for( const auto& tri : triangles )
241 totalArea += tri.Area();
242 std::cout << "\nTotal triangulated area: " << totalArea << std::endl;
243
244 // Calculate expected area of concave polygon for comparison
245 double originalArea = std::abs( concave.Area() );
246 std::cout << "Original polygon area: " << originalArea << std::endl;
247 std::cout << "Area difference: " << std::abs( totalArea - originalArea ) << std::endl;
248 }
249
250 std::cout << "================================================\n" << std::endl;
251 }
252
253 BOOST_TEST( success );
254 BOOST_TEST( isValid );
255 // L-shaped concave polygons should have 4 triangles
256 BOOST_TEST( triangleCount == 4 );
257}
258
259
260BOOST_AUTO_TEST_CASE( HintDataOptimization )
261{
262 // First triangulation without hint
264 auto triangulator1 = fixture1.CreateTriangulator();
266
267 bool success1 = triangulator1->TesselatePolygon( square, nullptr );
268 BOOST_TEST( success1 );
269
270 // Second triangulation with hint data from first
272 auto triangulator2 = fixture2.CreateTriangulator();
273
274 bool success2 = triangulator2->TesselatePolygon( square, &fixture1.GetResult() );
275 BOOST_TEST( success2 );
276
277 // Results should be identical when hint is applicable
278 BOOST_TEST( fixture1.GetResult().GetVertexCount() == fixture2.GetResult().GetVertexCount() );
279 BOOST_TEST( fixture1.GetResult().GetTriangleCount() == fixture2.GetResult().GetTriangleCount() );
280}
281
282BOOST_AUTO_TEST_CASE( HintDataInvalidation )
283{
284 // Create hint data with different vertex count
285 TRIANGULATION_TEST_FIXTURE hintFixture;
286 auto hintTriangulator = hintFixture.CreateTriangulator();
287 SHAPE_LINE_CHAIN triangle = createTriangle();
288 hintTriangulator->TesselatePolygon( triangle, nullptr );
289
290 // Try to use hint with different polygon (should ignore hint)
292 auto triangulator = fixture.CreateTriangulator();
294
295 bool success = triangulator->TesselatePolygon( square, &hintFixture.GetResult() );
296 BOOST_TEST( success );
298}
299
300// Degenerate case handling
301BOOST_AUTO_TEST_CASE( DegeneratePolygons )
302{
304 auto triangulator = fixture.CreateTriangulator();
305
306 // Test empty polygon
308 bool success = triangulator->TesselatePolygon( empty, nullptr );
309 BOOST_TEST( success ); // Should handle gracefully
310
311 // Test single point
313 auto triangulator2 = fixture2.CreateTriangulator();
314 SHAPE_LINE_CHAIN singlePoint;
315 singlePoint.Append( 0, 0 );
316 singlePoint.SetClosed( true );
317 success = triangulator2->TesselatePolygon( singlePoint, nullptr );
318 BOOST_TEST( success ); // Should handle gracefully
319
320 // Test two points (line segment)
322 auto triangulator3 = fixture3.CreateTriangulator();
323 SHAPE_LINE_CHAIN line;
324 line.Append( 0, 0 );
325 line.Append( 100, 0 );
326 line.SetClosed( true );
327 success = triangulator3->TesselatePolygon( line, nullptr );
328 BOOST_TEST( success ); // Should handle gracefully
329}
330
331BOOST_AUTO_TEST_CASE( ZeroAreaPolygon )
332{
334 auto triangulator = fixture.CreateTriangulator();
335
336 // Create a polygon with zero area (all points collinear)
337 SHAPE_LINE_CHAIN zeroArea;
338 zeroArea.Append( 0, 0 );
339 zeroArea.Append( 100, 0 );
340 zeroArea.Append( 50, 0 );
341 zeroArea.Append( 25, 0 );
342 zeroArea.SetClosed( true );
343
344 bool success = triangulator->TesselatePolygon( zeroArea, nullptr );
345
346 BOOST_TEST( success ); // Should handle gracefully without crashing
347}
348
349// Memory management and lifecycle tests
350BOOST_AUTO_TEST_CASE( MemoryManagement )
351{
352 // Test that multiple triangulations properly manage memory
353 for( int i = 0; i < 100; i++ )
354 {
356 auto triangulator = fixture.CreateTriangulator();
357
358 SHAPE_LINE_CHAIN poly = createSquare( 100 + i, VECTOR2I( i, i ) );
359 bool success = triangulator->TesselatePolygon( poly, nullptr );
360
361 BOOST_TEST( success );
362 BOOST_TEST( validateTriangulation( fixture.GetResult(), poly, false ) );
363 }
364}
365
366BOOST_AUTO_TEST_CASE( LargePolygonStressTest )
367{
369 auto triangulator = fixture.CreateTriangulator();
370
371 // Create a large polygon (regular polygon with many vertices)
372 SHAPE_LINE_CHAIN largePoly;
373 int numVertices = 1000;
374 int radius = 10000;
375
376 for( int i = 0; i < numVertices; i++ )
377 {
378 double angle = 2.0 * M_PI * i / numVertices;
379 int x = static_cast<int>( radius * cos( angle ) );
380 int y = static_cast<int>( radius * sin( angle ) );
381 largePoly.Append( x, y );
382 }
383 largePoly.SetClosed( true );
384
385 auto start = std::chrono::high_resolution_clock::now();
386 bool success = triangulator->TesselatePolygon( largePoly, nullptr );
387 auto end = std::chrono::high_resolution_clock::now();
388
389 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>( end - start );
390
391 BOOST_TEST( success );
392 if( success )
393 {
394 BOOST_TEST( validateTriangulation( fixture.GetResult(), largePoly, false ) );
395 BOOST_TEST( fixture.GetResult().GetTriangleCount() > 0 );
396 }
397
398 // Performance check - should complete in reasonable time
399 BOOST_TEST( duration.count() < 10000 ); // Less than 10 seconds
400}
401
402// Thread safety tests (following SHAPE_POLY_SET patterns)
403BOOST_AUTO_TEST_CASE( ConcurrentTriangulation )
404{
405 const int numThreads = 4;
406 const int numTriangulationsPerThread = 10;
407
408 std::vector<std::future<bool>> futures;
409
410 for( int t = 0; t < numThreads; t++ )
411 {
412 futures.push_back( std::async( std::launch::async, [t, numTriangulationsPerThread]()
413 {
414 for( int i = 0; i < numTriangulationsPerThread; i++ )
415 {
417 auto triangulator = fixture.CreateTriangulator();
418
419 // Create unique polygon for each thread/iteration
420 SHAPE_LINE_CHAIN poly = createSquare( 100 + t * 10 + i, VECTOR2I( t * 100, i * 100 ) );
421
422 bool success = triangulator->TesselatePolygon( poly, nullptr );
423 if( !success || !validateTriangulation( fixture.GetResult(), poly, false ) )
424 return false;
425 }
426 return true;
427 }));
428 }
429
430 // Wait for all threads and check results
431 for( auto& future : futures )
432 {
433 BOOST_TEST( future.get() );
434 }
435}
436
437// Edge case and robustness tests
438BOOST_AUTO_TEST_CASE( SelfIntersectingPolygon )
439{
441 auto triangulator = fixture.CreateTriangulator();
442
443 // Create a bowtie (self-intersecting polygon)
444 SHAPE_LINE_CHAIN bowtie;
445 bowtie.Append( 0, 0 );
446 bowtie.Append( 100, 100 );
447 bowtie.Append( 100, 0 );
448 bowtie.Append( 0, 100 );
449 bowtie.SetClosed( true );
450
451 bool success = triangulator->TesselatePolygon( bowtie, nullptr );
452
453 // Algorithm should handle self-intersecting polygons
454 BOOST_TEST( success );
455 if( success )
456 {
457 BOOST_TEST( validateTriangulation( fixture.GetResult(), bowtie, false ) );
458 }
459}
460
461BOOST_AUTO_TEST_CASE( NearlyCollinearVertices )
462{
464 auto triangulator = fixture.CreateTriangulator();
465
466 // Create a polygon with vertices that are nearly collinear
467 SHAPE_LINE_CHAIN nearlyCollinear;
468 nearlyCollinear.Append( 0, 0 );
469 nearlyCollinear.Append( 1000000, 0 );
470 nearlyCollinear.Append( 2000000, 1 ); // Very small deviation
471 nearlyCollinear.Append( 3000000, 0 );
472 nearlyCollinear.Append( 1500000, 1000000 );
473 nearlyCollinear.SetClosed( true );
474
475 bool success = triangulator->TesselatePolygon( nearlyCollinear, nullptr );
476
477 BOOST_TEST( success );
478 if( success )
479 {
480 BOOST_TEST( validateTriangulation( fixture.GetResult(), nearlyCollinear, false ) );
481 }
482}
483
484BOOST_AUTO_TEST_CASE( DuplicateVertices )
485{
487 auto triangulator = fixture.CreateTriangulator();
488
489 // Create a square with duplicate vertices
491 duplicate.Append( 0, 0 );
492 duplicate.Append( 0, 0 ); // Duplicate
493 duplicate.Append( 100, 0 );
494 duplicate.Append( 100, 0 ); // Duplicate
495 duplicate.Append( 100, 100 );
496 duplicate.Append( 100, 100 ); // Duplicate
497 duplicate.Append( 0, 100 );
498 duplicate.Append( 0, 100 ); // Duplicate
499 duplicate.SetClosed( true );
500
501 bool success = triangulator->TesselatePolygon( duplicate, nullptr );
502
503 BOOST_TEST( success );
504 if( success )
505 {
506 BOOST_TEST( validateTriangulation( fixture.GetResult(), duplicate, false ) );
507 }
508}
509
510BOOST_AUTO_TEST_CASE( ExtremeCoordinates )
511{
513 auto triangulator = fixture.CreateTriangulator();
514
515 // Test with very large coordinates
516 SHAPE_LINE_CHAIN extreme;
517 int large = 1000000000; // 1 billion
518 extreme.Append( 0, 0 );
519 extreme.Append( large, 0 );
520 extreme.Append( large, large );
521 extreme.Append( 0, large );
522 extreme.SetClosed( true );
523
524 bool success = triangulator->TesselatePolygon( extreme, nullptr );
525
526 BOOST_TEST( success );
527 if( success )
528 {
529 BOOST_TEST( validateTriangulation( fixture.GetResult(), extreme, false ) );
530 }
531}
532
533// Error recovery and cleanup tests
534BOOST_AUTO_TEST_CASE( ErrorRecoveryAndCleanup )
535{
537 auto triangulator = fixture.CreateTriangulator();
538
539 // Try a series of operations, some of which might fail
540 std::vector<SHAPE_LINE_CHAIN> testPolygons;
541
542 // Valid polygon
543 testPolygons.push_back( createSquare() );
544
545 // Degenerate polygon
546 SHAPE_LINE_CHAIN degenerate;
547 degenerate.Append( 0, 0 );
548 degenerate.SetClosed( true );
549 testPolygons.push_back( degenerate );
550
551 // Another valid polygon
552 testPolygons.push_back( createTriangle() );
553
554 for( const auto& poly : testPolygons )
555 {
556 // Each triangulation should start with a clean state
557 bool success = triangulator->TesselatePolygon( poly, nullptr );
558 // Even if triangulation fails, it should not crash
559 success |= fixture.GetResult().GetTriangleCount() > 0;
560 BOOST_TEST( success );
561 }
562}
563
564// Integration tests with TRIANGULATED_POLYGON interface
565BOOST_AUTO_TEST_CASE( TriangulatedPolygonInterface )
566{
568 auto triangulator = fixture.CreateTriangulator();
569
571 bool success = triangulator->TesselatePolygon( square, nullptr );
572
573 BOOST_TEST( success );
574
575 const auto& result = fixture.GetResult();
576
577 // Test GetTriangle method
578 if( result.GetTriangleCount() > 0 )
579 {
580 VECTOR2I a, b, c;
581 result.GetTriangle( 0, a, b, c );
582
583 // Vertices should be valid points from the square
584 BOOST_TEST( (a.x >= 0 && a.x <= 100 && a.y >= 0 && a.y <= 100) );
585 BOOST_TEST( (b.x >= 0 && b.x <= 100 && b.y >= 0 && b.y <= 100) );
586 BOOST_TEST( (c.x >= 0 && c.x <= 100 && c.y >= 0 && c.y <= 100) );
587 }
588
589 // Test triangle iteration
590 for( const auto& tri : result.Triangles() )
591 {
592 BOOST_TEST( tri.GetPointCount() == 3 );
593 BOOST_TEST( tri.GetSegmentCount() == 3 );
594 BOOST_TEST( tri.Area() > 0 );
595 BOOST_TEST( tri.IsClosed() );
596 BOOST_TEST( tri.IsSolid() );
597 }
598}
599
600BOOST_AUTO_TEST_CASE( SourceOutlineIndexTracking )
601{
603 auto triangulator = fixture.CreateTriangulator();
604
605 // Test that source outline index is properly maintained
606 const int expectedOutlineIndex = 5;
607
608 // Create triangulated polygon with specific source index
609 SHAPE_POLY_SET::TRIANGULATED_POLYGON result( expectedOutlineIndex );
610 POLYGON_TRIANGULATION localTriangulator( result );
611
612 SHAPE_LINE_CHAIN triangle = createTriangle();
613 bool success = localTriangulator.TesselatePolygon( triangle, nullptr );
614
615 BOOST_TEST( success );
616 BOOST_TEST( result.GetSourceOutlineIndex() == expectedOutlineIndex );
617}
618
619// Performance regression tests
620BOOST_AUTO_TEST_CASE( PerformanceRegression )
621{
622 // Test various polygon sizes to ensure performance scales reasonably
623 std::vector<int> testSizes = { 10, 50, 100, 500, 1000 };
624 std::vector<long long> durations;
625
626 for( int size : testSizes )
627 {
629 auto triangulator = fixture.CreateTriangulator();
630
631 // Create regular polygon
632 SHAPE_LINE_CHAIN poly;
633 for( int i = 0; i < size; i++ )
634 {
635 double angle = 2.0 * M_PI * i / size;
636 int x = static_cast<int>( 1000 * cos( angle ) );
637 int y = static_cast<int>( 1000 * sin( angle ) );
638 poly.Append( x, y );
639 }
640 poly.SetClosed( true );
641
642 auto start = std::chrono::high_resolution_clock::now();
643 bool success = triangulator->TesselatePolygon( poly, nullptr );
644 auto end = std::chrono::high_resolution_clock::now();
645
646 BOOST_TEST( success );
647
648 auto duration = std::chrono::duration_cast<std::chrono::microseconds>( end - start );
649 durations.push_back( duration.count() );
650 }
651
652 // Check that performance scales reasonably (shouldn't be exponential)
653 // This is a basic sanity check - actual performance will vary by hardware
654 for( size_t i = 1; i < durations.size(); i++ )
655 {
656 double scaleFactor = static_cast<double>( durations[i] ) / durations[i-1];
657 double sizeFactor = static_cast<double>( testSizes[i] ) / testSizes[i-1];
658
659 // Performance shouldn't be worse than O(n^2) in most cases
660 BOOST_TEST( scaleFactor < sizeFactor * sizeFactor * 2 );
661 }
662}
663
double square(double x)
bool TesselatePolygon(const SHAPE_LINE_CHAIN &aPoly, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const std::deque< VECTOR2I > & Vertices() const
const std::deque< TRI > & Triangles() const
Represent a set of closed polygons.
SHAPE_POLY_SET::TRIANGULATED_POLYGON & GetResult()
std::unique_ptr< POLYGON_TRIANGULATION > CreateTriangulator()
std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > m_result
static bool empty(const wxTextEntryBase *aCtrl)
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:400
Numerical test predicates.
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_TEST(contains==c.ExpectedContains)
BOOST_AUTO_TEST_SUITE_END()
SHAPE_LINE_CHAIN createConcavePolygon(int size=100)
SHAPE_LINE_CHAIN createSquare(int size=100, VECTOR2I offset=VECTOR2I(0, 0))
bool validateTriangulation(const SHAPE_POLY_SET::TRIANGULATED_POLYGON &result, const SHAPE_LINE_CHAIN &original, bool strict=true)
SHAPE_LINE_CHAIN createTriangle(int size=100, VECTOR2I offset=VECTOR2I(0, 0))
BOOST_AUTO_TEST_CASE(BasicTriangleTriangulation)
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695