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 );
358 for(
size_t zone = 0; zone < linear.size(); ++zone )
360 BOOST_REQUIRE_EQUAL( indexed[zone].OutlineCount(), linear[zone].OutlineCount() );
362 for(
int polygon = 0; polygon < linear[zone].OutlineCount(); ++polygon )
368 for(
int point = 0; point < a.
PointCount(); ++point )
378 std::vector<SHAPE_POLY_SET> zones;
388 polySet.CacheTriangulation();
390 for(
unsigned int i = 0; i < polySet.TriangulatedPolyCount(); ++i )
392 const auto* triPoly = polySet.TriangulatedPolygon(
static_cast<int>( i ) );
409 bool success = triangulator->TesselatePolygon( triangle,
nullptr );
424 bool success = triangulator->TesselatePolygon(
square,
nullptr );
437 std::vector<double> fractions =
443 for(
double fraction : fractions )
462 bool success = triangulator->TesselatePolygon( concave,
nullptr );
468 size_t triangleCount =
result.GetTriangleCount();
471 if( !success || !isValid || triangleCount < 4 )
473 std::cout <<
"\n=== ConcavePolygonTriangulation Diagnostic Output ===" << std::endl;
474 std::cout <<
"Success: " << (success ?
"true" :
"false") << std::endl;
475 std::cout <<
"Validation: " << (isValid ?
"true" :
"false") << std::endl;
476 std::cout <<
"Triangle count: " << triangleCount <<
" (expected >= 4)" << std::endl;
477 std::cout <<
"Vertex count: " <<
result.GetVertexCount() << std::endl;
480 std::cout <<
"\nInput polygon vertices (" << concave.
PointCount() <<
" points):" << std::endl;
481 for(
int i = 0; i < concave.
PointCount(); i++ )
484 std::cout <<
" [" << i <<
"]: (" << pt.
x <<
", " << pt.
y <<
")" << std::endl;
488 std::cout <<
"\nResult vertices (" <<
result.GetVertexCount() <<
" points):" << std::endl;
489 const auto& vertices =
result.Vertices();
490 for(
size_t i = 0; i < vertices.size(); i++ )
492 std::cout <<
" [" << i <<
"]: (" << vertices[i].x <<
", " << vertices[i].y <<
")" << std::endl;
496 std::cout <<
"\nTriangles found (" << triangleCount <<
" triangles):" << std::endl;
497 const auto& triangles =
result.Triangles();
498 for(
size_t i = 0; i < triangles.size(); i++ )
500 const auto& tri = triangles[i];
504 double area = tri.Area();
506 std::cout <<
" Triangle[" << i <<
"]: indices(" << tri.a <<
"," << tri.b <<
"," << tri.c <<
")" << std::endl;
507 std::cout <<
" A: (" << va.
x <<
", " << va.
y <<
")" << std::endl;
508 std::cout <<
" B: (" << vb.
x <<
", " << vb.
y <<
")" << std::endl;
509 std::cout <<
" C: (" << vc.
x <<
", " << vc.
y <<
")" << std::endl;
510 std::cout <<
" Area: " << area << std::endl;
514 std::cout <<
" *** DEGENERATE TRIANGLE (area <= 0) ***" << std::endl;
515 if( tri.a == tri.b || tri.b == tri.c || tri.a == tri.c )
516 std::cout <<
" *** INVALID TRIANGLE (duplicate vertex indices) ***" << std::endl;
520 if( triangleCount > 0 )
523 for(
const auto& tri : triangles )
525 std::cout <<
"\nTotal triangulated area: " <<
totalArea << std::endl;
529 std::cout <<
"Original polygon area: " << originalArea << std::endl;
530 std::cout <<
"Area difference: " <<
std::abs(
totalArea - originalArea ) << std::endl;
533 std::cout <<
"================================================\n" << std::endl;
550 bool success1 = triangulator1->TesselatePolygon(
square,
nullptr );
557 bool success2 = triangulator2->TesselatePolygon(
square, &fixture1.
GetResult() );
568 noisySquare.
Append( 0, 0 );
569 noisySquare.
Append( 100, 0 );
570 noisySquare.
Append( 100, 10 );
571 noisySquare.
Append( 100, 100 );
572 noisySquare.
Append( 0, 100 );
578 bool success1 = hintTriangulator->TesselatePolygon( noisySquare,
nullptr );
582 BOOST_REQUIRE_GE( poisonedTriangles.size(), 2U );
583 std::reverse( poisonedTriangles.begin(), poisonedTriangles.end() );
589 bool success2 = triangulator->TesselatePolygon( noisySquare, &hintFixture.
GetResult() );
593 for(
size_t i = 0; i < poisonedTriangles.size(); ++i )
607 hintTriangulator->TesselatePolygon( triangle,
nullptr );
614 bool success = triangulator->TesselatePolygon(
square, &hintFixture.
GetResult() );
627 bool success = triangulator->TesselatePolygon(
empty,
nullptr );
634 singlePoint.
Append( 0, 0 );
636 success = triangulator2->TesselatePolygon( singlePoint,
nullptr );
646 success = triangulator3->TesselatePolygon( line,
nullptr );
658 zeroArea.
Append( 100, 0 );
663 bool success = triangulator->TesselatePolygon( zeroArea,
nullptr );
672 for(
int i = 0; i < 100; i++ )
678 bool success = triangulator->TesselatePolygon( poly,
nullptr );
692 int numVertices = 1000;
695 for(
int i = 0; i < numVertices; i++ )
697 double angle = 2.0 *
M_PI * i / numVertices;
698 int x =
static_cast<int>(
radius * cos( angle ) );
699 int y =
static_cast<int>(
radius * sin( angle ) );
704 auto start = std::chrono::high_resolution_clock::now();
705 bool success = triangulator->TesselatePolygon( largePoly,
nullptr );
706 auto end = std::chrono::high_resolution_clock::now();
708 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end - start );
718#if defined( KICAD_SANITIZE_THREADS ) || defined( KICAD_SANITIZE_ADDRESS )
728 const int numThreads = 4;
729 const int numTriangulationsPerThread = 10;
731 std::vector<std::future<bool>> futures;
733 for(
int t = 0; t < numThreads; t++ )
735 futures.push_back( std::async( std::launch::async, [t, numTriangulationsPerThread]()
737 for(
int i = 0; i < numTriangulationsPerThread; i++ )
745 bool success = triangulator->TesselatePolygon( poly,
nullptr );
754 for(
auto& future : futures )
769 bowtie.
Append( 100, 100 );
774 bool success = triangulator->TesselatePolygon( bowtie,
nullptr );
803 const int SCALE = 1000000;
804 outline.
Append( 165 * SCALE, 87 * SCALE );
805 outline.
Append( 179 * SCALE, 87 * SCALE );
806 outline.
Append( 174 * SCALE, 94 * SCALE );
807 outline.
Append( 169 * SCALE, 87 * SCALE );
808 outline.
Append( 167 * SCALE, 94 * SCALE );
821 double triangulatedArea = 0.0;
827 for(
const auto& tri : triPoly->Triangles() )
828 triangulatedArea +=
std::abs( tri.Area() );
834 double expectedAreaMmSq = 49.0 * SCALE * SCALE;
837 BOOST_TEST(
std::abs( triangulatedArea - expectedAreaMmSq ) < expectedAreaMmSq * 0.01,
838 "Triangulated area should match expected area of 49 mm²" );
843 const int SCALE = 1000000;
844 const std::array<VECTOR2I, 5> corners = {
VECTOR2I( 165 * SCALE, 87 * SCALE ),
845 VECTOR2I( 179 * SCALE, 87 * SCALE ),
846 VECTOR2I( 174 * SCALE, 94 * SCALE ),
847 VECTOR2I( 169 * SCALE, 87 * SCALE ),
848 VECTOR2I( 167 * SCALE, 94 * SCALE ) };
852 for(
size_t i = 0; i < corners.size(); ++i )
855 const VECTOR2I& b = corners[( i + 1 ) % corners.size()];
857 for(
int step = 0; step < 8; ++step )
858 outline.
Append( a.
x + ( b.
x - a.
x ) * step / 8, a.
y + ( b.
y - a.
y ) * step / 8 );
862 BOOST_REQUIRE_EQUAL( outline.
PointCount(), 40 );
866 const double outlineArea = polySet.
Area();
871 double triangulatedArea = 0.0;
877 for(
const auto& tri : triPoly->Triangles() )
878 triangulatedArea +=
std::abs( tri.Area() );
909 const VECTOR2I inHole( 64000, 50000 );
910 std::vector<const SHAPE*> triangles;
915 for(
const SHAPE* tri : triangles )
926 nearlyCollinear.
Append( 0, 0 );
927 nearlyCollinear.
Append( 1000000, 0 );
928 nearlyCollinear.
Append( 2000000, 1 );
929 nearlyCollinear.
Append( 3000000, 0 );
930 nearlyCollinear.
Append( 1500000, 1000000 );
933 bool success = triangulator->TesselatePolygon( nearlyCollinear,
nullptr );
959 bool success = triangulator->TesselatePolygon(
duplicate,
nullptr );
975 int large = 1000000000;
977 extreme.
Append( large, 0 );
978 extreme.
Append( large, large );
979 extreme.
Append( 0, large );
982 bool success = triangulator->TesselatePolygon( extreme,
nullptr );
998 std::vector<SHAPE_LINE_CHAIN> testPolygons;
1005 degenerate.Append( 0, 0 );
1006 degenerate.SetClosed(
true );
1007 testPolygons.push_back( degenerate );
1012 for(
const auto& poly : testPolygons )
1015 bool success = triangulator->TesselatePolygon( poly,
nullptr );
1029 bool success = triangulator->TesselatePolygon(
square,
nullptr );
1036 if(
result.GetTriangleCount() > 0 )
1039 result.GetTriangle( 0, a, b, c );
1042 BOOST_TEST( (a.
x >= 0 && a.
x <= 100 && a.
y >= 0 && a.
y <= 100) );
1043 BOOST_TEST( (b.
x >= 0 && b.
x <= 100 && b.
y >= 0 && b.
y <= 100) );
1044 BOOST_TEST( (c.
x >= 0 && c.
x <= 100 && c.
y >= 0 && c.
y <= 100) );
1048 for(
const auto& tri :
result.Triangles() )
1064 const int expectedOutlineIndex = 5;
1081 std::vector<int> testSizes = { 10, 50, 100, 500, 1000 };
1082 std::vector<long long> durations;
1084 for(
int size : testSizes )
1091 for(
int i = 0; i < size; i++ )
1093 double angle = 2.0 *
M_PI * i / size;
1094 int x =
static_cast<int>( 1000 * cos( angle ) );
1095 int y =
static_cast<int>( 1000 * sin( angle ) );
1100 auto start = std::chrono::high_resolution_clock::now();
1101 bool success = triangulator->TesselatePolygon( poly,
nullptr );
1102 auto end = std::chrono::high_resolution_clock::now();
1106 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
end - start );
1107 durations.push_back( duration.count() );
1112 for(
size_t i = 1; i < durations.size(); i++ )
1114 double scaleFactor =
static_cast<double>( durations[i] ) / durations[i-1];
1115 double sizeFactor =
static_cast<double>( testSizes[i] ) / testSizes[i-1];
1118 BOOST_TEST( scaleFactor < sizeFactor * sizeFactor * 2 );
1131 constexpr int vertexCount = 120000;
1132 constexpr int centerX = 5000000;
1133 constexpr int centerY = 5000000;
1134 constexpr int radius = 4000000;
1136 for(
int i = 0; i < vertexCount; ++i )
1138 double angle = 2.0 *
M_PI * i / vertexCount;
1139 int x = centerX +
static_cast<int>(
radius * cos( angle ) );
1140 int y = centerY +
static_cast<int>(
radius * sin( angle ) );
1147 std::atomic<int> tasksSubmitted( 0 );
1150 [&tasksSubmitted]( std::function<void()> aTask )
1153 std::thread( std::move( aTask ) ).detach();
1162 double triArea = 0.0;
1168 for(
const auto& tri : triPoly->Triangles() )
1173 if( originalArea > 0.0 )
1175 double coverage = triArea / originalArea;
1194 outer.
Append( 10000, 0 );
1195 outer.
Append( 10000, 10000 );
1196 outer.
Append( 0, 10000 );
1201 hole.
Append( 1000, 1000 );
1206 polygon.push_back( outer );
1207 polygon.push_back( hole );
1212 std::atomic<bool> finished(
false );
1215 std::thread worker( [&]()
1217 result = triangulator->TesselatePolygon( polygon,
nullptr );
1218 finished.store(
true );
1223 auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds( 5 );
1225 while( !finished.load() && std::chrono::steady_clock::now() < deadline )
1226 std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
1228 BOOST_CHECK_MESSAGE( finished.load(),
"TesselatePolygon hung (issue #24059)" );
1230 if( finished.load() )
1258 outer.
Append( 10000, 0 );
1259 outer.
Append( 10000, 10000 );
1260 outer.
Append( 0, 10000 );
1267 hole.
Append( 5000, 5000 );
1268 hole.
Append( 5000, 5000 );
1269 hole.
Append( 5000, 5000 );
1270 hole.
Append( 5000, 5000 );
1274 polygon.push_back( outer );
1275 polygon.push_back( hole );
1280 bool result = triangulator->TesselatePolygon( polygon,
nullptr );
1296 outer.
Append( 10000, 0 );
1297 outer.
Append( 10000, 10000 );
1298 outer.
Append( 0, 10000 );
1305 tinyHole.
Append( 5000, 5000 );
1306 tinyHole.
Append( 5002, 5000 );
1307 tinyHole.
Append( 5002, 5002 );
1308 tinyHole.
Append( 5000, 5002 );
1312 polygon.push_back( outer );
1313 polygon.push_back( tinyHole );
1318 bool result = triangulator->TesselatePolygon( polygon,
nullptr );
1328 outline.
Append( 10000, 0 );
1329 outline.
Append( 10000, 10000 );
1330 outline.
Append( 0, 10000 );
1339 polySet.
Move( { 1, 1 } );
1350 outline.
Append( 10000, 0 );
1351 outline.
Append( 10000, 10000 );
1352 outline.
Append( 0, 10000 );
1369 double minAngle = 180.0;
1371 for(
const auto& tri : aTri.
Triangles() )
1375 tri.GetPoint( 2 ) ) );
1386 for(
const auto& tri : aTri.
Triangles() )
1395 for(
const auto& tri : aTri.
Triangles() )
1397 bool hasU = tri.a == aU || tri.b == aU || tri.c == aU;
1398 bool hasV = tri.a == aV || tri.b == aV || tri.c == aV;
1412 for(
const auto& tri : aTri.
Triangles() )
1414 VECTOR2I a = tri.GetPoint( 0 ), b = tri.GetPoint( 1 ), c = tri.GetPoint( 2 );
1434 tp.AddTriangle( 0, 1, 2 );
1435 tp.AddTriangle( 0, 2, 3 );
1437 double beforeAngle = meshMinAngleDeg(
tp );
1438 double beforeArea = meshArea(
tp );
1443 BOOST_CHECK_CLOSE( meshArea(
tp ), beforeArea, 0.001 );
1444 BOOST_CHECK_GT( meshMinAngleDeg(
tp ), beforeAngle );
1446 BOOST_CHECK( meshHasEdge(
tp, 0, 1 ) );
1447 BOOST_CHECK( meshHasEdge(
tp, 1, 2 ) );
1448 BOOST_CHECK( meshHasEdge(
tp, 2, 3 ) );
1449 BOOST_CHECK( meshHasEdge(
tp, 0, 3 ) );
1451 BOOST_CHECK( !meshHasEdge(
tp, 0, 2 ) );
1452 BOOST_CHECK( meshHasEdge(
tp, 1, 3 ) );
1465 tp.AddTriangle( 0, 1, 2 );
1466 tp.AddTriangle( 0, 2, 3 );
1472 BOOST_REQUIRE_EQUAL( meshSpikeyCount(
tp ), 1 );
1474 double beforeArea = meshArea(
tp );
1479 BOOST_CHECK_CLOSE( meshArea(
tp ), beforeArea, 0.001 );
1481 BOOST_CHECK( !meshHasEdge(
tp, 0, 2 ) );
1482 BOOST_CHECK( meshHasEdge(
tp, 1, 3 ) );
1495 tp.AddTriangle( 0, 1, 2 );
1496 tp.AddTriangle( 0, 2, 3 );
1498 double beforeArea = meshArea(
tp );
1503 BOOST_CHECK_CLOSE( meshArea(
tp ), beforeArea, 0.001 );
1504 BOOST_CHECK( meshHasEdge(
tp, 0, 2 ) );
1533 tp.AddTriangle( 0, 1, 2 );
1534 tp.AddTriangle( 0, 1, 3 );
1535 tp.AddTriangle( 0, 1, 4 );
1537 std::vector<int> before;
1539 for(
const auto& tri :
tp.Triangles() )
1541 before.push_back( tri.a );
1542 before.push_back( tri.b );
1543 before.push_back( tri.c );
1548 std::vector<int> after;
1550 for(
const auto& tri :
tp.Triangles() )
1552 after.push_back( tri.a );
1553 after.push_back( tri.b );
1554 after.push_back( tri.c );
1557 BOOST_CHECK( before == after );
1558 BOOST_CHECK( meshHasEdge(
tp, 0, 1 ) );
1567 const int size = 1000000;
1568 const int steps = 20;
1570 for(
int i = 0; i < steps; i++ )
1571 chain.Append( i * size / steps, 0 );
1573 for(
int i = 0; i < steps; i++ )
1574 chain.Append( size, i * size / steps );
1576 for(
int i = 0; i < steps; i++ )
1577 chain.Append( size - i * size / steps, size );
1579 for(
int i = 0; i < steps; i++ )
1580 chain.Append( 0, size - i * size / steps );
1582 chain.SetClosed(
true );
1589 BOOST_CHECK_CLOSE( meshArea( fixture.
GetResult() ), (
double) size * size, 1e-6 );
1600 const int halfPitch = 25000;
1601 const int teeth = 10;
1603 for(
int i = 0; i <= teeth * 2; i++ )
1604 chain.Append( i * halfPitch, ( i % 2 ) ? amp : 0 );
1606 chain.Append( teeth * 2 * halfPitch, -5000000 );
1607 chain.Append( 0, -5000000 );
1608 chain.SetClosed(
true );
1615 static_cast<size_t>(
chain.PointCount() ) - 2 );
1626 const int size = 1000000;
1627 const int steps = 25;
1630 for(
int i = 0; i < steps; i++ )
1631 outline.
Append( i * size / steps, 0 );
1633 for(
int i = 0; i < steps; i++ )
1634 outline.
Append( size, i * size / steps );
1636 for(
int i = 0; i < steps; i++ )
1637 outline.
Append( size - i * size / steps, size );
1639 for(
int i = 0; i < steps; i++ )
1640 outline.
Append( 0, size - i * size / steps );
1645 hole.
Append( 400000, 400000 );
1646 hole.
Append( 400000, 600000 );
1647 hole.
Append( 600000, 600000 );
1648 hole.
Append( 600000, 400000 );
1655 const double area = poly.
Area();
1660 double meshTotal = 0.0;
1661 size_t triangles = 0;
1668 meshTotal += tri.Area();
1671 BOOST_CHECK_CLOSE( meshTotal, area, 1e-6 );
1675 BOOST_CHECK_LT( triangles, 20u );
static double square(double x)
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.
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={}, bool aBuildIndexes=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
bool Parse(std::stringstream &aStream) override
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