40 size_t aTargetLeaves )
46namespace fs = std::filesystem;
51 bool Contains(
const wxString& aText )
const {
return m_text.Contains( aText ); }
72 wxLog::AddTraceMask(
m_mask );
78 wxLog::RemoveTraceMask(
m_mask );
81 bool Contains(
const wxString& aText )
const {
return m_log->Contains( aText ); }
103 return std::make_unique<POLYGON_TRIANGULATION>( *
m_result );
107 std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>
m_result;
114 chain.Append( offset.x, offset.y );
115 chain.Append( offset.x + size, offset.y );
116 chain.Append( offset.x + size, offset.y + size );
117 chain.Append( offset.x, offset.y + size );
118 chain.SetClosed(
true );
126 chain.Append( offset.x, offset.y );
127 chain.Append( offset.x + size, offset.y );
128 chain.Append( offset.x + size/2, offset.y + size );
129 chain.SetClosed(
true );
137 chain.Append( 0, 0 );
138 chain.Append( size, 0 );
139 chain.Append( size, size/2 );
140 chain.Append( size/2, size/2 );
141 chain.Append( size/2, size );
142 chain.Append( 0, size );
143 chain.SetClosed(
true );
150 chain.Append( 0, 0 );
154 for(
int ii = 0; ii < teeth; ++ii )
157 chain.Append( x, 0 );
158 chain.Append( x, step * 3 );
160 chain.Append( x, step * 3 );
161 chain.Append( x, step * 4 );
164 chain.Append( 0, step * 4 );
165 chain.SetClosed(
true );
174 if(
result.GetVertexCount() == 0 )
177 size_t triangleCount =
result.GetTriangleCount();
178 if( triangleCount == 0 )
182 for(
size_t i = 0; i < triangleCount; i++ )
184 const auto& triangle =
result.Triangles()[i];
187 if( triangle.a >= (
int)
result.GetVertexCount() ||
188 triangle.b >= (
int)
result.GetVertexCount() ||
189 triangle.c >= (
int)
result.GetVertexCount() )
195 if( triangle.a == triangle.b || triangle.b == triangle.c || triangle.a == triangle.c )
199 if( strict && triangle.Area() <= 0 )
206 const auto& vertices =
result.Vertices();
207 for(
int i = 0; i < original.
PointCount(); i++ )
210 for(
size_t j = 0; j < vertices.size(); j++ )
212 if( vertices[j] == original.
CPoint( i ) )
230 for(
const auto& tri : aResult.
Triangles() )
240 double longest = std::max( { ab, bc, ca } );
241 double shortest = std::min( { ab, bc, ca } );
243 if( shortest > 0.0 && longest / shortest > 10.0 )
252 std::ifstream file( aPath );
254 if( !file.is_open() )
257 std::string content( ( std::istreambuf_iterator<char>( file ) ),
258 std::istreambuf_iterator<char>() );
262 while( ( zonePos = content.find(
"(zone (layer \"", zonePos ) ) != std::string::npos )
264 size_t polysetStart = content.find(
"polyset ", zonePos );
266 if( polysetStart != std::string::npos )
269 std::string remainder = content.substr( polysetStart );
270 std::stringstream ss( remainder );
272 if( polySet.
Parse( ss ) )
273 aZones.push_back( std::move( polySet ) );
276 size_t layerEnd = content.find(
"\")", zonePos + 14 );
278 if( layerEnd == std::string::npos )
281 zonePos = layerEnd + 1;
284 return !aZones.empty();
296 m_cfg.m_EnableCacheFriendlyFracture =
true;
297 m_cfg.m_EnableFractureEdgeIndex = aUseIndex;
315#if !defined( __MINGW32__ )
317 std::vector<SHAPE_POLY_SET> zones;
327 for(
int polygon = 0; polygon < zone.OutlineCount(); ++polygon )
328 deepest = std::max( deepest, zone.HoleCount( polygon ) );
333 BOOST_REQUIRE_GE( deepest, 100 );
335 std::vector<SHAPE_POLY_SET> linear = zones;
336 std::vector<SHAPE_POLY_SET> indexed = zones;
342 zone.Fracture(
false );
351 zone.Fracture(
false );
356 for(
size_t zone = 0; zone < linear.size(); ++zone )
358 BOOST_REQUIRE_EQUAL( indexed[zone].OutlineCount(), linear[zone].OutlineCount() );
360 for(
int polygon = 0; polygon < linear[zone].OutlineCount(); ++polygon )
366 for(
int point = 0; point < a.
PointCount(); ++point )
376 std::vector<SHAPE_POLY_SET> zones;
386 polySet.CacheTriangulation();
388 for(
unsigned int i = 0; i < polySet.TriangulatedPolyCount(); ++i )
390 const auto* triPoly = polySet.TriangulatedPolygon(
static_cast<int>( i ) );
407 bool success = triangulator->TesselatePolygon( triangle,
nullptr );
422 bool success = triangulator->TesselatePolygon(
square,
nullptr );
435 std::vector<double> fractions =
441 for(
double fraction : fractions )
460 bool success = triangulator->TesselatePolygon( concave,
nullptr );
466 size_t triangleCount =
result.GetTriangleCount();
469 if( !success || !isValid || triangleCount < 4 )
471 std::cout <<
"\n=== ConcavePolygonTriangulation Diagnostic Output ===" << std::endl;
472 std::cout <<
"Success: " << (success ?
"true" :
"false") << std::endl;
473 std::cout <<
"Validation: " << (isValid ?
"true" :
"false") << std::endl;
474 std::cout <<
"Triangle count: " << triangleCount <<
" (expected >= 4)" << std::endl;
475 std::cout <<
"Vertex count: " <<
result.GetVertexCount() << std::endl;
478 std::cout <<
"\nInput polygon vertices (" << concave.
PointCount() <<
" points):" << std::endl;
479 for(
int i = 0; i < concave.
PointCount(); i++ )
482 std::cout <<
" [" << i <<
"]: (" << pt.
x <<
", " << pt.
y <<
")" << std::endl;
486 std::cout <<
"\nResult vertices (" <<
result.GetVertexCount() <<
" points):" << std::endl;
487 const auto& vertices =
result.Vertices();
488 for(
size_t i = 0; i < vertices.size(); i++ )
490 std::cout <<
" [" << i <<
"]: (" << vertices[i].x <<
", " << vertices[i].y <<
")" << std::endl;
494 std::cout <<
"\nTriangles found (" << triangleCount <<
" triangles):" << std::endl;
495 const auto& triangles =
result.Triangles();
496 for(
size_t i = 0; i < triangles.size(); i++ )
498 const auto& tri = triangles[i];
502 double area = tri.Area();
504 std::cout <<
" Triangle[" << i <<
"]: indices(" << tri.a <<
"," << tri.b <<
"," << tri.c <<
")" << std::endl;
505 std::cout <<
" A: (" << va.
x <<
", " << va.
y <<
")" << std::endl;
506 std::cout <<
" B: (" << vb.
x <<
", " << vb.
y <<
")" << std::endl;
507 std::cout <<
" C: (" << vc.
x <<
", " << vc.
y <<
")" << std::endl;
508 std::cout <<
" Area: " << area << std::endl;
512 std::cout <<
" *** DEGENERATE TRIANGLE (area <= 0) ***" << std::endl;
513 if( tri.a == tri.b || tri.b == tri.c || tri.a == tri.c )
514 std::cout <<
" *** INVALID TRIANGLE (duplicate vertex indices) ***" << std::endl;
518 if( triangleCount > 0 )
521 for(
const auto& tri : triangles )
523 std::cout <<
"\nTotal triangulated area: " <<
totalArea << std::endl;
527 std::cout <<
"Original polygon area: " << originalArea << std::endl;
528 std::cout <<
"Area difference: " <<
std::abs(
totalArea - originalArea ) << std::endl;
531 std::cout <<
"================================================\n" << std::endl;
548 bool success1 = triangulator1->TesselatePolygon(
square,
nullptr );
555 bool success2 = triangulator2->TesselatePolygon(
square, &fixture1.
GetResult() );
566 noisySquare.
Append( 0, 0 );
567 noisySquare.
Append( 100, 0 );
568 noisySquare.
Append( 100, 10 );
569 noisySquare.
Append( 100, 100 );
570 noisySquare.
Append( 0, 100 );
576 bool success1 = hintTriangulator->TesselatePolygon( noisySquare,
nullptr );
580 BOOST_REQUIRE_GE( poisonedTriangles.size(), 2U );
581 std::reverse( poisonedTriangles.begin(), poisonedTriangles.end() );
587 bool success2 = triangulator->TesselatePolygon( noisySquare, &hintFixture.
GetResult() );
591 for(
size_t i = 0; i < poisonedTriangles.size(); ++i )
605 hintTriangulator->TesselatePolygon( triangle,
nullptr );
612 bool success = triangulator->TesselatePolygon(
square, &hintFixture.
GetResult() );
625 bool success = triangulator->TesselatePolygon(
empty,
nullptr );
632 singlePoint.
Append( 0, 0 );
634 success = triangulator2->TesselatePolygon( singlePoint,
nullptr );
644 success = triangulator3->TesselatePolygon( line,
nullptr );
656 zeroArea.
Append( 100, 0 );
661 bool success = triangulator->TesselatePolygon( zeroArea,
nullptr );
670 for(
int i = 0; i < 100; i++ )
676 bool success = triangulator->TesselatePolygon( poly,
nullptr );
690 int numVertices = 1000;
693 for(
int i = 0; i < numVertices; i++ )
695 double angle = 2.0 *
M_PI * i / numVertices;
696 int x =
static_cast<int>(
radius * cos( angle ) );
697 int y =
static_cast<int>(
radius * sin( angle ) );
702 auto start = std::chrono::high_resolution_clock::now();
703 bool success = triangulator->TesselatePolygon( largePoly,
nullptr );
704 auto end = std::chrono::high_resolution_clock::now();
706 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end - start );
716#if defined( KICAD_SANITIZE_THREADS ) || defined( KICAD_SANITIZE_ADDRESS )
726 const int numThreads = 4;
727 const int numTriangulationsPerThread = 10;
729 std::vector<std::future<bool>> futures;
731 for(
int t = 0; t < numThreads; t++ )
733 futures.push_back( std::async( std::launch::async, [t, numTriangulationsPerThread]()
735 for(
int i = 0; i < numTriangulationsPerThread; i++ )
743 bool success = triangulator->TesselatePolygon( poly,
nullptr );
752 for(
auto& future : futures )
767 bowtie.
Append( 100, 100 );
772 bool success = triangulator->TesselatePolygon( bowtie,
nullptr );
801 const int SCALE = 1000000;
802 outline.
Append( 165 * SCALE, 87 * SCALE );
803 outline.
Append( 179 * SCALE, 87 * SCALE );
804 outline.
Append( 174 * SCALE, 94 * SCALE );
805 outline.
Append( 169 * SCALE, 87 * SCALE );
806 outline.
Append( 167 * SCALE, 94 * SCALE );
819 double triangulatedArea = 0.0;
825 for(
const auto& tri : triPoly->Triangles() )
826 triangulatedArea +=
std::abs( tri.Area() );
832 double expectedAreaMmSq = 49.0 * SCALE * SCALE;
835 BOOST_TEST(
std::abs( triangulatedArea - expectedAreaMmSq ) < expectedAreaMmSq * 0.01,
836 "Triangulated area should match expected area of 49 mm²" );
841 const int SCALE = 1000000;
842 const std::array<VECTOR2I, 5> corners = {
VECTOR2I( 165 * SCALE, 87 * SCALE ),
843 VECTOR2I( 179 * SCALE, 87 * SCALE ),
844 VECTOR2I( 174 * SCALE, 94 * SCALE ),
845 VECTOR2I( 169 * SCALE, 87 * SCALE ),
846 VECTOR2I( 167 * SCALE, 94 * SCALE ) };
850 for(
size_t i = 0; i < corners.size(); ++i )
853 const VECTOR2I& b = corners[( i + 1 ) % corners.size()];
855 for(
int step = 0; step < 8; ++step )
856 outline.
Append( a.
x + ( b.
x - a.
x ) * step / 8, a.
y + ( b.
y - a.
y ) * step / 8 );
860 BOOST_REQUIRE_EQUAL( outline.
PointCount(), 40 );
864 const double outlineArea = polySet.
Area();
869 double triangulatedArea = 0.0;
875 for(
const auto& tri : triPoly->Triangles() )
876 triangulatedArea +=
std::abs( tri.Area() );
907 const VECTOR2I inHole( 64000, 50000 );
908 std::vector<const SHAPE*> triangles;
913 for(
const SHAPE* tri : triangles )
924 nearlyCollinear.
Append( 0, 0 );
925 nearlyCollinear.
Append( 1000000, 0 );
926 nearlyCollinear.
Append( 2000000, 1 );
927 nearlyCollinear.
Append( 3000000, 0 );
928 nearlyCollinear.
Append( 1500000, 1000000 );
931 bool success = triangulator->TesselatePolygon( nearlyCollinear,
nullptr );
957 bool success = triangulator->TesselatePolygon(
duplicate,
nullptr );
973 int large = 1000000000;
975 extreme.
Append( large, 0 );
976 extreme.
Append( large, large );
977 extreme.
Append( 0, large );
980 bool success = triangulator->TesselatePolygon( extreme,
nullptr );
996 std::vector<SHAPE_LINE_CHAIN> testPolygons;
1003 degenerate.Append( 0, 0 );
1004 degenerate.SetClosed(
true );
1005 testPolygons.push_back( degenerate );
1010 for(
const auto& poly : testPolygons )
1013 bool success = triangulator->TesselatePolygon( poly,
nullptr );
1027 bool success = triangulator->TesselatePolygon(
square,
nullptr );
1034 if(
result.GetTriangleCount() > 0 )
1037 result.GetTriangle( 0, a, b, c );
1040 BOOST_TEST( (a.
x >= 0 && a.
x <= 100 && a.
y >= 0 && a.
y <= 100) );
1041 BOOST_TEST( (b.
x >= 0 && b.
x <= 100 && b.
y >= 0 && b.
y <= 100) );
1042 BOOST_TEST( (c.
x >= 0 && c.
x <= 100 && c.
y >= 0 && c.
y <= 100) );
1046 for(
const auto& tri :
result.Triangles() )
1062 const int expectedOutlineIndex = 5;
1079 std::vector<int> testSizes = { 10, 50, 100, 500, 1000 };
1080 std::vector<long long> durations;
1082 for(
int size : testSizes )
1089 for(
int i = 0; i < size; i++ )
1091 double angle = 2.0 *
M_PI * i / size;
1092 int x =
static_cast<int>( 1000 * cos( angle ) );
1093 int y =
static_cast<int>( 1000 * sin( angle ) );
1098 auto start = std::chrono::high_resolution_clock::now();
1099 bool success = triangulator->TesselatePolygon( poly,
nullptr );
1100 auto end = std::chrono::high_resolution_clock::now();
1104 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end - start );
1105 durations.push_back( duration.count() );
1110 for(
size_t i = 1; i < durations.size(); i++ )
1112 double scaleFactor =
static_cast<double>( durations[i] ) / durations[i-1];
1113 double sizeFactor =
static_cast<double>( testSizes[i] ) / testSizes[i-1];
1116 BOOST_TEST( scaleFactor < sizeFactor * sizeFactor * 2 );
1129 constexpr int vertexCount = 120000;
1130 constexpr int centerX = 5000000;
1131 constexpr int centerY = 5000000;
1132 constexpr int radius = 4000000;
1134 for(
int i = 0; i < vertexCount; ++i )
1136 double angle = 2.0 *
M_PI * i / vertexCount;
1137 int x = centerX +
static_cast<int>(
radius * cos( angle ) );
1138 int y = centerY +
static_cast<int>(
radius * sin( angle ) );
1145 std::atomic<int> tasksSubmitted( 0 );
1148 [&tasksSubmitted]( std::function<void()> aTask )
1151 std::thread( std::move( aTask ) ).detach();
1160 double triArea = 0.0;
1166 for(
const auto& tri : triPoly->Triangles() )
1171 if( originalArea > 0.0 )
1173 double coverage = triArea / originalArea;
1192 outer.
Append( 10000, 0 );
1193 outer.
Append( 10000, 10000 );
1194 outer.
Append( 0, 10000 );
1199 hole.
Append( 1000, 1000 );
1204 polygon.push_back( outer );
1205 polygon.push_back( hole );
1210 std::atomic<bool> finished(
false );
1213 std::thread worker( [&]()
1215 result = triangulator->TesselatePolygon( polygon,
nullptr );
1216 finished.store(
true );
1221 auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds( 5 );
1223 while( !finished.load() && std::chrono::steady_clock::now() < deadline )
1224 std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
1226 BOOST_CHECK_MESSAGE( finished.load(),
"TesselatePolygon hung (issue #24059)" );
1228 if( finished.load() )
1256 outer.
Append( 10000, 0 );
1257 outer.
Append( 10000, 10000 );
1258 outer.
Append( 0, 10000 );
1265 hole.
Append( 5000, 5000 );
1266 hole.
Append( 5000, 5000 );
1267 hole.
Append( 5000, 5000 );
1268 hole.
Append( 5000, 5000 );
1272 polygon.push_back( outer );
1273 polygon.push_back( hole );
1278 bool result = triangulator->TesselatePolygon( polygon,
nullptr );
1294 outer.
Append( 10000, 0 );
1295 outer.
Append( 10000, 10000 );
1296 outer.
Append( 0, 10000 );
1303 tinyHole.
Append( 5000, 5000 );
1304 tinyHole.
Append( 5002, 5000 );
1305 tinyHole.
Append( 5002, 5002 );
1306 tinyHole.
Append( 5000, 5002 );
1310 polygon.push_back( outer );
1311 polygon.push_back( tinyHole );
1316 bool result = triangulator->TesselatePolygon( polygon,
nullptr );
1326 outline.
Append( 10000, 0 );
1327 outline.
Append( 10000, 10000 );
1328 outline.
Append( 0, 10000 );
1337 polySet.
Move( { 1, 1 } );
1348 outline.
Append( 10000, 0 );
1349 outline.
Append( 10000, 10000 );
1350 outline.
Append( 0, 10000 );
1367 double minAngle = 180.0;
1369 for(
const auto& tri : aTri.
Triangles() )
1373 tri.GetPoint( 2 ) ) );
1384 for(
const auto& tri : aTri.
Triangles() )
1393 for(
const auto& tri : aTri.
Triangles() )
1395 bool hasU = tri.a == aU || tri.b == aU || tri.c == aU;
1396 bool hasV = tri.a == aV || tri.b == aV || tri.c == aV;
1410 for(
const auto& tri : aTri.
Triangles() )
1412 VECTOR2I a = tri.GetPoint( 0 ), b = tri.GetPoint( 1 ), c = tri.GetPoint( 2 );
1432 tp.AddTriangle( 0, 1, 2 );
1433 tp.AddTriangle( 0, 2, 3 );
1435 double beforeAngle = meshMinAngleDeg(
tp );
1436 double beforeArea = meshArea(
tp );
1441 BOOST_CHECK_CLOSE( meshArea(
tp ), beforeArea, 0.001 );
1442 BOOST_CHECK_GT( meshMinAngleDeg(
tp ), beforeAngle );
1444 BOOST_CHECK( meshHasEdge(
tp, 0, 1 ) );
1445 BOOST_CHECK( meshHasEdge(
tp, 1, 2 ) );
1446 BOOST_CHECK( meshHasEdge(
tp, 2, 3 ) );
1447 BOOST_CHECK( meshHasEdge(
tp, 0, 3 ) );
1449 BOOST_CHECK( !meshHasEdge(
tp, 0, 2 ) );
1450 BOOST_CHECK( meshHasEdge(
tp, 1, 3 ) );
1463 tp.AddTriangle( 0, 1, 2 );
1464 tp.AddTriangle( 0, 2, 3 );
1470 BOOST_REQUIRE_EQUAL( meshSpikeyCount(
tp ), 1 );
1472 double beforeArea = meshArea(
tp );
1477 BOOST_CHECK_CLOSE( meshArea(
tp ), beforeArea, 0.001 );
1479 BOOST_CHECK( !meshHasEdge(
tp, 0, 2 ) );
1480 BOOST_CHECK( meshHasEdge(
tp, 1, 3 ) );
1493 tp.AddTriangle( 0, 1, 2 );
1494 tp.AddTriangle( 0, 2, 3 );
1496 double beforeArea = meshArea(
tp );
1501 BOOST_CHECK_CLOSE( meshArea(
tp ), beforeArea, 0.001 );
1502 BOOST_CHECK( meshHasEdge(
tp, 0, 2 ) );
1531 tp.AddTriangle( 0, 1, 2 );
1532 tp.AddTriangle( 0, 1, 3 );
1533 tp.AddTriangle( 0, 1, 4 );
1535 std::vector<int> before;
1537 for(
const auto& tri :
tp.Triangles() )
1539 before.push_back( tri.a );
1540 before.push_back( tri.b );
1541 before.push_back( tri.c );
1546 std::vector<int> after;
1548 for(
const auto& tri :
tp.Triangles() )
1550 after.push_back( tri.a );
1551 after.push_back( tri.b );
1552 after.push_back( tri.c );
1555 BOOST_CHECK( before == after );
1556 BOOST_CHECK( meshHasEdge(
tp, 0, 1 ) );
1565 const int size = 1000000;
1566 const int steps = 20;
1568 for(
int i = 0; i < steps; i++ )
1569 chain.Append( i * size / steps, 0 );
1571 for(
int i = 0; i < steps; i++ )
1572 chain.Append( size, i * size / steps );
1574 for(
int i = 0; i < steps; i++ )
1575 chain.Append( size - i * size / steps, size );
1577 for(
int i = 0; i < steps; i++ )
1578 chain.Append( 0, size - i * size / steps );
1580 chain.SetClosed(
true );
1587 BOOST_CHECK_CLOSE( meshArea( fixture.
GetResult() ), (
double) size * size, 1e-6 );
1598 const int halfPitch = 25000;
1599 const int teeth = 10;
1601 for(
int i = 0; i <= teeth * 2; i++ )
1602 chain.Append( i * halfPitch, ( i % 2 ) ? amp : 0 );
1604 chain.Append( teeth * 2 * halfPitch, -5000000 );
1605 chain.Append( 0, -5000000 );
1606 chain.SetClosed(
true );
1613 static_cast<size_t>(
chain.PointCount() ) - 2 );
1624 const int size = 1000000;
1625 const int steps = 25;
1628 for(
int i = 0; i < steps; i++ )
1629 outline.
Append( i * size / steps, 0 );
1631 for(
int i = 0; i < steps; i++ )
1632 outline.
Append( size, i * size / steps );
1634 for(
int i = 0; i < steps; i++ )
1635 outline.
Append( size - i * size / steps, size );
1637 for(
int i = 0; i < steps; i++ )
1638 outline.
Append( 0, size - i * size / steps );
1643 hole.
Append( 400000, 400000 );
1644 hole.
Append( 400000, 600000 );
1645 hole.
Append( 600000, 600000 );
1646 hole.
Append( 600000, 400000 );
1653 const double area = poly.
Area();
1658 double meshTotal = 0.0;
1659 size_t triangles = 0;
1666 meshTotal += tri.Area();
1669 BOOST_CHECK_CLOSE( meshTotal, area, 1e-6 );
1673 BOOST_CHECK_LT( triangles, 20u );
bool TesselatePolygon(const SHAPE_POLY_SET::POLYGON &aPolygon, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
Triangulate a polygon with holes by bridging holes directly into the outer ring's VERTEX linked list,...
std::vector< double > PartitionAreaFractionsForTesting(const SHAPE_LINE_CHAIN &aPoly, size_t aTargetLeaves) const
SCOPED_FRACTURE_CFG(bool aUseIndex)
SCOPED_TRACE_CAPTURE(const wxString &aMask)
bool Contains(const wxString &aText) const
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.
size_t GetTriangleCount() const
const std::deque< TRI > & Triangles() const
size_t GetVertexCount() const
void SetTriangles(const std::deque< TRI > &aTriangles)
Represent a set of closed polygons.
virtual void GetIndexableSubshapes(std::vector< const SHAPE * > &aSubshapes) const override
bool IsTriangulationUpToDate() const
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
double Area()
Return the area of this poly set.
bool Parse(std::stringstream &aStream) override
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={})
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
void UpdateTriangulationDataHash()
void Move(const VECTOR2I &aVector) override
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
std::function< void(std::function< void()>)> TASK_SUBMITTER
Callback that submits a unit of work for asynchronous execution.
bool IsSelfIntersecting() const
Check whether any of the polygons in the set is self intersecting.
An abstract shape on 2D plane.
bool Contains(const wxString &aText) const
void DoLogTextAtLevel(wxLogLevel, const wxString &aText) override
SHAPE_POLY_SET::TRIANGULATED_POLYGON & GetResult()
std::unique_ptr< POLYGON_TRIANGULATION > CreateTriangulator()
std::unique_ptr< SHAPE_POLY_SET::TRIANGULATED_POLYGON > m_result
TRIANGULATION_TEST_FIXTURE()
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
static bool empty(const wxTextEntryBase *aCtrl)
Exact orientation and in-circle predicates over integer coordinates.
double TriangleMinAngleDeg(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c)
The smallest interior angle of a triangle, in degrees; near zero for a sliver.
int OrientationSign(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c)
Orientation of triangle (a, b, c): +1 counter-clockwise, -1 clockwise, 0 collinear.
bool InCircleDelaunayLegal(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c, const VECTOR2I &p)
True when p is outside the circumcircle of CCW triangle (a, b, c): the shared edge is already Delauna...
bool IsSliverTriangle(const VECTOR2I &a, const VECTOR2I &b, const VECTOR2I &c)
A triangle is a sliver when its longest edge exceeds ten times its shortest.
std::string GetTestDataRootDir()
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Numerical test predicates.
#define TRIANGULATESIMPLIFICATIONLEVEL
static std::vector< double > PartitionAreaFractions(POLYGON_TRIANGULATION &aTriangulator, const SHAPE_LINE_CHAIN &aPoly, size_t aTargetLeaves)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST(netlist.find("R_G1 ARM_OUT1 DIE_B R='0.001 / ((SW_STATE)") !=std::string::npos)
bool parsePolyFileForTest(const fs::path &aPath, std::vector< SHAPE_POLY_SET > &aZones)
SHAPE_LINE_CHAIN createConcavePolygon(int size=100)
int countSpikeyTriangles(const SHAPE_POLY_SET::TRIANGULATED_POLYGON &aResult)
BOOST_AUTO_TEST_CASE(FractureEdgeIndexMatchesLinearScan)
SHAPE_LINE_CHAIN createSquare(int size=100, VECTOR2I offset=VECTOR2I(0, 0))
double computeBoardSpikeyRatio(const fs::path &aPath)
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))
SHAPE_LINE_CHAIN createSerpentinePolygon(int step=20000, int teeth=16)
const SHAPE_LINE_CHAIN chain
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I