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
461
474BOOST_AUTO_TEST_CASE( Issue18083_SelfIntersectingPolygonArea )
475{
476 SHAPE_POLY_SET polySet;
477 SHAPE_LINE_CHAIN outline;
478
479 // Coordinates from the issue (converted to internal units: 1mm = 1000000)
480 const int SCALE = 1000000;
481 outline.Append( 165 * SCALE, 87 * SCALE );
482 outline.Append( 179 * SCALE, 87 * SCALE );
483 outline.Append( 174 * SCALE, 94 * SCALE );
484 outline.Append( 169 * SCALE, 87 * SCALE );
485 outline.Append( 167 * SCALE, 94 * SCALE );
486 outline.SetClosed( true );
487
488 polySet.AddOutline( outline );
489
490 // Verify the polygon is detected as self-intersecting
491 BOOST_TEST( polySet.IsSelfIntersecting() );
492
493 // Triangulate via SHAPE_POLY_SET
494 polySet.CacheTriangulation( false );
496
497 // Calculate the triangulated area
498 double triangulatedArea = 0.0;
499
500 for( int ii = 0; ii < polySet.TriangulatedPolyCount(); ii++ )
501 {
502 const auto triPoly = polySet.TriangulatedPolygon( ii );
503
504 for( const auto& tri : triPoly->Triangles() )
505 triangulatedArea += std::abs( tri.Area() );
506 }
507
508 // The expected total area is 49 mm² (14 mm² + 35 mm² for the two triangular lobes)
509 // Triangle 1: (165,87) - (169,87) - (167,94) = base 4mm, height 7mm = 14 mm²
510 // Triangle 2: (169,87) - (179,87) - (174,94) = base 10mm, height 7mm = 35 mm²
511 double expectedAreaMmSq = 49.0 * SCALE * SCALE;
512
513 // The triangulated area should match the expected area
514 BOOST_TEST( std::abs( triangulatedArea - expectedAreaMmSq ) < expectedAreaMmSq * 0.01,
515 "Triangulated area should match expected area of 49 mm²" );
516}
517
518BOOST_AUTO_TEST_CASE( NearlyCollinearVertices )
519{
521 auto triangulator = fixture.CreateTriangulator();
522
523 // Create a polygon with vertices that are nearly collinear
524 SHAPE_LINE_CHAIN nearlyCollinear;
525 nearlyCollinear.Append( 0, 0 );
526 nearlyCollinear.Append( 1000000, 0 );
527 nearlyCollinear.Append( 2000000, 1 ); // Very small deviation
528 nearlyCollinear.Append( 3000000, 0 );
529 nearlyCollinear.Append( 1500000, 1000000 );
530 nearlyCollinear.SetClosed( true );
531
532 bool success = triangulator->TesselatePolygon( nearlyCollinear, nullptr );
533
534 BOOST_TEST( success );
535 if( success )
536 {
537 BOOST_TEST( validateTriangulation( fixture.GetResult(), nearlyCollinear, false ) );
538 }
539}
540
541BOOST_AUTO_TEST_CASE( DuplicateVertices )
542{
544 auto triangulator = fixture.CreateTriangulator();
545
546 // Create a square with duplicate vertices
548 duplicate.Append( 0, 0 );
549 duplicate.Append( 0, 0 ); // Duplicate
550 duplicate.Append( 100, 0 );
551 duplicate.Append( 100, 0 ); // Duplicate
552 duplicate.Append( 100, 100 );
553 duplicate.Append( 100, 100 ); // Duplicate
554 duplicate.Append( 0, 100 );
555 duplicate.Append( 0, 100 ); // Duplicate
556 duplicate.SetClosed( true );
557
558 bool success = triangulator->TesselatePolygon( duplicate, nullptr );
559
560 BOOST_TEST( success );
561 if( success )
562 {
563 BOOST_TEST( validateTriangulation( fixture.GetResult(), duplicate, false ) );
564 }
565}
566
567BOOST_AUTO_TEST_CASE( ExtremeCoordinates )
568{
570 auto triangulator = fixture.CreateTriangulator();
571
572 // Test with very large coordinates
573 SHAPE_LINE_CHAIN extreme;
574 int large = 1000000000; // 1 billion
575 extreme.Append( 0, 0 );
576 extreme.Append( large, 0 );
577 extreme.Append( large, large );
578 extreme.Append( 0, large );
579 extreme.SetClosed( true );
580
581 bool success = triangulator->TesselatePolygon( extreme, nullptr );
582
583 BOOST_TEST( success );
584 if( success )
585 {
586 BOOST_TEST( validateTriangulation( fixture.GetResult(), extreme, false ) );
587 }
588}
589
590// Error recovery and cleanup tests
591BOOST_AUTO_TEST_CASE( ErrorRecoveryAndCleanup )
592{
594 auto triangulator = fixture.CreateTriangulator();
595
596 // Try a series of operations, some of which might fail
597 std::vector<SHAPE_LINE_CHAIN> testPolygons;
598
599 // Valid polygon
600 testPolygons.push_back( createSquare() );
601
602 // Degenerate polygon
603 SHAPE_LINE_CHAIN degenerate;
604 degenerate.Append( 0, 0 );
605 degenerate.SetClosed( true );
606 testPolygons.push_back( degenerate );
607
608 // Another valid polygon
609 testPolygons.push_back( createTriangle() );
610
611 for( const auto& poly : testPolygons )
612 {
613 // Each triangulation should start with a clean state
614 bool success = triangulator->TesselatePolygon( poly, nullptr );
615 // Even if triangulation fails, it should not crash
616 success |= fixture.GetResult().GetTriangleCount() > 0;
617 BOOST_TEST( success );
618 }
619}
620
621// Integration tests with TRIANGULATED_POLYGON interface
622BOOST_AUTO_TEST_CASE( TriangulatedPolygonInterface )
623{
625 auto triangulator = fixture.CreateTriangulator();
626
628 bool success = triangulator->TesselatePolygon( square, nullptr );
629
630 BOOST_TEST( success );
631
632 const auto& result = fixture.GetResult();
633
634 // Test GetTriangle method
635 if( result.GetTriangleCount() > 0 )
636 {
637 VECTOR2I a, b, c;
638 result.GetTriangle( 0, a, b, c );
639
640 // Vertices should be valid points from the square
641 BOOST_TEST( (a.x >= 0 && a.x <= 100 && a.y >= 0 && a.y <= 100) );
642 BOOST_TEST( (b.x >= 0 && b.x <= 100 && b.y >= 0 && b.y <= 100) );
643 BOOST_TEST( (c.x >= 0 && c.x <= 100 && c.y >= 0 && c.y <= 100) );
644 }
645
646 // Test triangle iteration
647 for( const auto& tri : result.Triangles() )
648 {
649 BOOST_TEST( tri.GetPointCount() == 3 );
650 BOOST_TEST( tri.GetSegmentCount() == 3 );
651 BOOST_TEST( tri.Area() > 0 );
652 BOOST_TEST( tri.IsClosed() );
653 BOOST_TEST( tri.IsSolid() );
654 }
655}
656
657BOOST_AUTO_TEST_CASE( SourceOutlineIndexTracking )
658{
660 auto triangulator = fixture.CreateTriangulator();
661
662 // Test that source outline index is properly maintained
663 const int expectedOutlineIndex = 5;
664
665 // Create triangulated polygon with specific source index
666 SHAPE_POLY_SET::TRIANGULATED_POLYGON result( expectedOutlineIndex );
667 POLYGON_TRIANGULATION localTriangulator( result );
668
669 SHAPE_LINE_CHAIN triangle = createTriangle();
670 bool success = localTriangulator.TesselatePolygon( triangle, nullptr );
671
672 BOOST_TEST( success );
673 BOOST_TEST( result.GetSourceOutlineIndex() == expectedOutlineIndex );
674}
675
676// Performance regression tests
677BOOST_AUTO_TEST_CASE( PerformanceRegression )
678{
679 // Test various polygon sizes to ensure performance scales reasonably
680 std::vector<int> testSizes = { 10, 50, 100, 500, 1000 };
681 std::vector<long long> durations;
682
683 for( int size : testSizes )
684 {
686 auto triangulator = fixture.CreateTriangulator();
687
688 // Create regular polygon
689 SHAPE_LINE_CHAIN poly;
690 for( int i = 0; i < size; i++ )
691 {
692 double angle = 2.0 * M_PI * i / size;
693 int x = static_cast<int>( 1000 * cos( angle ) );
694 int y = static_cast<int>( 1000 * sin( angle ) );
695 poly.Append( x, y );
696 }
697 poly.SetClosed( true );
698
699 auto start = std::chrono::high_resolution_clock::now();
700 bool success = triangulator->TesselatePolygon( poly, nullptr );
701 auto end = std::chrono::high_resolution_clock::now();
702
703 BOOST_TEST( success );
704
705 auto duration = std::chrono::duration_cast<std::chrono::microseconds>( end - start );
706 durations.push_back( duration.count() );
707 }
708
709 // Check that performance scales reasonably (shouldn't be exponential)
710 // This is a basic sanity check - actual performance will vary by hardware
711 for( size_t i = 1; i < durations.size(); i++ )
712 {
713 double scaleFactor = static_cast<double>( durations[i] ) / durations[i-1];
714 double sizeFactor = static_cast<double>( testSizes[i] ) / testSizes[i-1];
715
716 // Performance shouldn't be worse than O(n^2) in most cases
717 BOOST_TEST( scaleFactor < sizeFactor * sizeFactor * 2 );
718 }
719}
720
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.
Represent a set of closed polygons.
bool IsTriangulationUpToDate() const
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
bool IsSelfIntersecting() const
Check whether any of the polygons in the set is self intersecting.
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
wxString result
Test unit parsing edge cases and error handling.
#define M_PI
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695