278 if( aStop.stop_requested() )
285#ifdef PRINT_STATISTICS_3D_VIEWER
288 int64_t start_Time = stats_startCopperLayersTime;
306 std::vector<const PCB_TRACK*> trackList;
308 trackList.reserve(
m_board->Tracks().size() );
320 trackList.push_back( track );
342 std::vector<PCB_LAYER_ID> layer_ids;
351 layer_ids.push_back( layer );
378 if( aStop.stop_requested() )
381 if( aStatusReporter )
382 aStatusReporter->Report(
_(
"Create tracks and vias" ) );
391 for(
const PCB_TRACK* track : trackList )
394 if( !track->IsOnLayer( layer ) )
406 if( aStop.stop_requested() )
419 unsigned int nTracks = trackList.size();
421 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
423 const PCB_TRACK *track = trackList[trackIdx];
438 const float thickness =
static_cast<float>( plating / 2.0f );
439 const float hole_inner_radius =
static_cast<float>( holediameter / 2.0f );
440 const float ring_radius =
static_cast<float>( viasize / 2.0f );
457 else if( layer == layer_ids[0] )
469 if( hole_inner_radius > 0.0 )
475 const double frontRadius =
via->GetFrontPostMachiningSize() *
m_biuTo3Dunits / 2.0;
479 && frontRadius > hole_inner_radius )
481 if( layer == layer_ids[0] )
490 layerHoleContainer->
Add(
new FILLED_CIRCLE_2D( via_center, frontRadius + thickness, *track ) );
494 const double backRadius =
via->GetBackPostMachiningSize() *
m_biuTo3Dunits / 2.0;
498 && backRadius > hole_inner_radius )
501 if( layer == layer_ids.back() )
510 layerHoleContainer->
Add(
new FILLED_CIRCLE_2D( via_center, backRadius + thickness, *track ) );
514 float backdrillRadius =
via->GetSecondaryDrillSize().value_or( 0 ) *
m_biuTo3Dunits / 2.0f ;
517 if( backdrillRadius > hole_inner_radius + thickness )
522 bool validLyPair = secStart >= 0 && secEnd >= 0;
532 if( validLyPair && layer == secStart )
537 float tertiaryDrillRadius =
via->GetTertiaryDrillSize().value_or( 0 ) *
m_biuTo3Dunits / 2.0f ;
540 if( tertiaryDrillRadius > hole_inner_radius + thickness )
545 bool validLyPair = terStart >= 0 && terEnd >= 0;
552 layerHoleContainer->
Add(
new FILLED_CIRCLE_2D( via_center, tertiaryDrillRadius, *track ) );
555 if( validLyPair && layer == terStart )
572 if( aStop.stop_requested() )
590 const unsigned int nTracks = trackList.size();
592 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
594 const PCB_TRACK *track = trackList[trackIdx];
616 const int holediameter =
via->GetDrillValue();
628 else if( layer == layer_ids[0] )
630 const int hole_outer_ring_radius =
KiROUND(
via->GetWidth( layer ) / 2.0 );
648 const auto frontMode =
via->GetFrontPostMachining();
650 if( frontMode.has_value()
654 const int frontRadiusBIU =
via->GetFrontPostMachiningSize() / 2;
656 if( frontRadiusBIU > holediameter / 2 )
678 const auto backMode =
via->GetBackPostMachining();
680 if( backMode.has_value()
684 const int backRadiusBIU =
via->GetBackPostMachiningSize() / 2;
686 if( backRadiusBIU > holediameter / 2 )
709 const auto secondaryDrillSize =
via->GetSecondaryDrillSize();
711 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
713 const int backdrillRadiusBIU = secondaryDrillSize.value() / 2;
715 const int holeOuterRadiusBIU = hole_outer_radius;
718 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
722 bool validLyPair = secStart >= 0 && secEnd >= 0;
740 const auto tertiaryDrillSize =
via->GetTertiaryDrillSize();
742 if( tertiaryDrillSize.has_value() && tertiaryDrillSize.value() > 0 )
744 const int backdrillRadiusBIU = tertiaryDrillSize.value() / 2;
746 const int holeOuterRadiusBIU = hole_outer_radius;
749 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
753 bool validLyPair = terStart >= 0 && terEnd >= 0;
772 if( aStop.stop_requested() )
787 unsigned int nTracks = trackList.size();
789 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
791 const PCB_TRACK *track = trackList[trackIdx];
806 if( aStop.stop_requested() )
812 for(
PAD*
pad : footprint->Pads() )
815 if( !
pad->HasHole() )
819 double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
842 const float holeDiameterUnits =
static_cast<float>( (
pad->GetDrillSize().x +
pad->GetDrillSize().y )
844 const float holeInnerRadius = holeDiameterUnits / 2.0f;
848 const auto frontMode =
pad->GetFrontPostMachining();
850 if( frontMode.has_value()
854 float frontRadius =
pad->GetFrontPostMachiningSize() * 0.5f *
static_cast<float>(
m_biuTo3Dunits );
856 if( frontRadius > holeInnerRadius )
869 const auto backMode =
pad->GetBackPostMachining();
871 if( backMode.has_value()
875 float backRadius =
pad->GetBackPostMachiningSize() * 0.5f *
static_cast<float>(
m_biuTo3Dunits );
877 if( backRadius > holeInnerRadius )
891 const VECTOR2I& secDrillSize =
pad->GetSecondaryDrillSize();
893 if( secDrillSize.
x > 0 || secDrillSize.
y > 0 )
895 const float backdrillRadius = ( secDrillSize.
x + secDrillSize.
y ) * 0.25f
899 const float holeOuterRadius = holeInnerRadius
903 if( backdrillRadius > holeOuterRadius )
907 bool validLyPair = secStart >= 0 && secEnd >= 0;
934 if( aStop.stop_requested() )
944 for(
PAD*
pad : footprint->Pads() )
946 if( !
pad->HasHole() )
970 const double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
971 const int holeRadius =
KiROUND( holeDiameter / 2.0 );
973 const std::optional<PAD_DRILL_POST_MACHINING_MODE> frontMode =
pad->GetFrontPostMachining();
975 if( frontMode.has_value()
979 const int frontRadiusBIU =
pad->GetFrontPostMachiningSize() / 2;
981 if( frontRadiusBIU > holeRadius )
996 const std::optional<PAD_DRILL_POST_MACHINING_MODE> backMode =
pad->GetBackPostMachining();
998 if( backMode.has_value()
1002 const int backRadiusBIU =
pad->GetBackPostMachiningSize() / 2;
1004 if( backRadiusBIU > holeRadius )
1020 const VECTOR2I& secondaryDrillSize =
pad->GetSecondaryDrillSize();
1022 if( secondaryDrillSize.
x > 0 || secondaryDrillSize.
y > 0 )
1024 const int secondaryRadiusBIU = ( secondaryDrillSize.
x + secondaryDrillSize.
y ) / 4;
1025 const int holeOuterRadiusBIU = holeRadius + inflate;
1028 if( secondaryRadiusBIU > holeOuterRadiusBIU )
1032 bool validLayerPair = secondaryStart >= 0 && secondaryEnd >= 0;
1034 if( validLayerPair )
1063 const VECTOR2I& tertiaryDrillSize =
pad->GetTertiaryDrillSize();
1065 if( tertiaryDrillSize.
x > 0 || tertiaryDrillSize.
y > 0 )
1067 const int tertiaryRadiusBIU = ( tertiaryDrillSize.
x + tertiaryDrillSize.
y ) / 4;
1068 const int holeOuterRadiusBIU = holeRadius + inflate;
1071 if( tertiaryRadiusBIU > holeOuterRadiusBIU )
1075 bool validLayerPair = tertiaryStart >= 0 && tertiaryEnd >= 0;
1077 if( validLayerPair )
1107 if( aStop.stop_requested() )
1120 addPads( fp, layerContainer, layer );
1128 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(),
ERROR_INSIDE );
1140 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(),
ERROR_INSIDE );
1145 if( aStop.stop_requested() )
1160 if( !item->IsOnLayer( layer ) )
1163 switch( item->Type() )
1197 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ), item->Type() );
1214 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, text_box->
GetMaxError(),
1224 item->TransformShapeToPolySet( *copperPolys, layer, 0, item->GetMaxError(),
ERROR_INSIDE );
1235 switch( item->Type() )
1238 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(),
ERROR_INSIDE );
1255 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->
GetMaxError(),
1268 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(),
ERROR_INSIDE );
1298 for(
const std::shared_ptr<SHAPE>& shape : dimension->
GetShapes() )
1308 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ), item->Type() );
1314 if( aStop.stop_requested() )
1318 if( aStop.stop_requested() )
1323 if( aStatusReporter )
1324 aStatusReporter->Report(
_(
"Create zones" ) );
1326 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
1327 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
1333 zones.emplace_back( std::make_pair( zone, layer ) );
1334 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
1340 zone->TransformShapeToPolygon( *copperPolys, layer, 0, zone->GetMaxError(),
ERROR_INSIDE );
1344 if( aStop.stop_requested() )
1349 std::atomic<size_t> nextZone( 0 );
1350 std::atomic<size_t> threadsFinished( 0 );
1352 size_t parallelThreadCount = std::min<size_t>( zones.size(),
1353 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
1355 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1357 std::thread t = std::thread( [&]()
1359 for(
size_t areaId = nextZone.fetch_add( 1 );
1360 areaId < zones.size();
1361 areaId = nextZone.fetch_add( 1 ) )
1363 ZONE* zone = zones[areaId].first;
1365 if( zone ==
nullptr )
1376 auto mut_it = layer_lock.find( layer );
1378 if( mut_it != layer_lock.end() )
1380 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
1392 while( threadsFinished < parallelThreadCount )
1393 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1397 if( aStop.stop_requested() )
1438 if( aStatusReporter )
1439 aStatusReporter->Report(
_(
"Build Tech layers" ) );
1509 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
1517 if( aStop.stop_requested() )
1522 if( aStatusReporter )
1523 aStatusReporter->Report( wxString::Format(
_(
"Build Tech layer %d" ), (
int) layer ) );
1539 if( !item->IsOnLayer( layer ) )
1542 switch( item->Type() )
1582 if( !track->IsOnLayer( layer ) )
1592 if( !
via->FlashLayer( copper_layer ) )
1596 int maskExpansion = track->GetSolderMaskExpansion();
1610 for(
PAD*
pad : footprint->Pads() )
1612 if( !
pad->IsOnLayer( layer ) )
1620 addPads( footprint, layerContainer, layer );
1631 if( zone->IsOnLayer( layer ) )
1637 if( aStop.stop_requested() )
1648 if( !item->IsOnLayer( layer ) )
1651 switch( item->Type() )
1693 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(),
ERROR_INSIDE );
1719 if( aStop.stop_requested() )
1733 if(
via->FlashLayer( layer ) && !
via->IsTented( layer ) )
1735 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1741 if( track->HasSolderMask() )
1743 track->TransformShapeToPolySet( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1750 if( aStop.stop_requested() )
1760 for(
PAD*
pad : footprint->Pads() )
1762 if(
pad->IsOnLayer( layer ) )
1771 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, footprint->GetMaxError(),
ERROR_INSIDE );
1779 if( aStop.stop_requested() )
1786 if( zone->IsOnLayer( layer ) )
1787 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1791 if( aStop.stop_requested() )
1797 if( aStop.stop_requested() )
1803 if( aStop.stop_requested() )
1814 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1816 if( footprint->IsFlipped() )
1827 if( aStop.stop_requested() )
1831 if( aStatusReporter )
1832 aStatusReporter->Report(
_(
"Simplifying copper layer polygons" ) );
1836 if( aStatusReporter )
1837 aStatusReporter->Report(
_(
"Calculating plated copper" ) );
1863 if( aStop.stop_requested() )
1869 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1870 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1874 layer_id_without_F_and_B.clear();
1875 layer_id_without_F_and_B.reserve( layer_ids.size() );
1879 if( layer !=
F_Cu && layer !=
B_Cu )
1880 layer_id_without_F_and_B.push_back( layer );
1883 selected_layer_id = layer_id_without_F_and_B;
1886 if( selected_layer_id.size() > 0 )
1888 if( aStatusReporter )
1890 aStatusReporter->Report( wxString::Format(
_(
"Simplifying %d copper layers" ),
1891 (
int) selected_layer_id.size() ) );
1894 std::atomic<size_t> nextItem( 0 );
1895 std::atomic<size_t> threadsFinished( 0 );
1897 size_t parallelThreadCount = std::min<size_t>(
1898 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1899 selected_layer_id.size() );
1901 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1903 std::thread t = std::thread(
1904 [&nextItem, &threadsFinished, &selected_layer_id,
this]()
1906 for(
size_t i = nextItem.fetch_add( 1 );
1907 i < selected_layer_id.size();
1908 i = nextItem.fetch_add( 1 ) )
1924 while( threadsFinished < parallelThreadCount )
1925 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1928 if( aStop.stop_requested() )
1933 if( aStatusReporter )
1934 aStatusReporter->Report(
_(
"Simplify holes contours" ) );
1950 if( aStop.stop_requested() )
1956 if( aStatusReporter )
1957 aStatusReporter->Report(
_(
"Build BVH for holes and vias" ) );
1963 if( aStop.stop_requested() )
1973 if( aStop.stop_requested() )
1978 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole :
m_layerHoleMap )
1979 hole.second->BuildBVH();
1982 if( aStop.stop_requested() )