212#ifdef PRINT_STATISTICS_3D_VIEWER
215 int64_t start_Time = stats_startCopperLayersTime;
233 std::vector<const PCB_TRACK*> trackList;
235 trackList.reserve(
m_board->Tracks().size() );
247 trackList.push_back( track );
269 std::vector<PCB_LAYER_ID> layer_ids;
278 layer_ids.push_back( layer );
305 if( aStatusReporter )
306 aStatusReporter->
Report(
_(
"Create tracks and vias" ) );
315 for(
const PCB_TRACK* track : trackList )
318 if( !track->IsOnLayer( layer ) )
340 unsigned int nTracks = trackList.size();
342 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
344 const PCB_TRACK *track = trackList[trackIdx];
359 const float thickness =
static_cast<float>( plating / 2.0f );
360 const float hole_inner_radius =
static_cast<float>( holediameter / 2.0f );
361 const float ring_radius =
static_cast<float>( viasize / 2.0f );
376 else if( layer == layer_ids[0] )
385 if( hole_inner_radius > 0.0 )
391 const double frontRadius =
via->GetFrontPostMachiningSize() *
m_biuTo3Dunits / 2.0;
395 && frontRadius > hole_inner_radius )
397 if( layer == layer_ids[0] )
406 layerHoleContainer->
Add(
new FILLED_CIRCLE_2D( via_center, frontRadius + thickness, *track ) );
410 const double backRadius =
via->GetBackPostMachiningSize() *
m_biuTo3Dunits / 2.0;
414 && backRadius > hole_inner_radius )
417 if( layer == layer_ids.back() )
426 layerHoleContainer->
Add(
new FILLED_CIRCLE_2D( via_center, backRadius + thickness, *track ) );
430 float backdrillRadius =
via->GetSecondaryDrillSize().value_or( 0 ) *
m_biuTo3Dunits / 2.0f ;
433 if( backdrillRadius > hole_inner_radius + thickness )
446 if( layer == secStart )
451 float tertiaryDrillRadius =
via->GetTertiaryDrillSize().value_or( 0 ) *
m_biuTo3Dunits / 2.0f ;
454 if( tertiaryDrillRadius > hole_inner_radius + thickness )
464 layerHoleContainer->
Add(
new FILLED_CIRCLE_2D( via_center, tertiaryDrillRadius, *track ) );
467 if( layer == terStart )
499 const unsigned int nTracks = trackList.size();
501 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
503 const PCB_TRACK *track = trackList[trackIdx];
525 const int holediameter =
via->GetDrillValue();
537 else if( layer == layer_ids[0] )
539 const int hole_outer_ring_radius =
KiROUND(
via->GetWidth( layer ) / 2.0 );
557 const auto frontMode =
via->GetFrontPostMachining();
559 if( frontMode.has_value()
563 const int frontRadiusBIU =
via->GetFrontPostMachiningSize() / 2;
565 if( frontRadiusBIU > holediameter / 2 )
572 frontRadiusBIU,
via->GetMaxError(),
578 frontRadiusBIU,
via->GetMaxError(),
583 frontRadiusOuterBIU,
via->GetMaxError(),
586 frontRadiusBIU,
via->GetMaxError(),
591 const auto backMode =
via->GetBackPostMachining();
593 if( backMode.has_value()
597 const int backRadiusBIU =
via->GetBackPostMachiningSize() / 2;
599 if( backRadiusBIU > holediameter / 2 )
606 backRadiusBIU,
via->GetMaxError(),
612 backRadiusBIU,
via->GetMaxError(),
617 backRadiusOuterBIU,
via->GetMaxError(),
620 backRadiusBIU,
via->GetMaxError(),
626 const auto secondaryDrillSize =
via->GetSecondaryDrillSize();
628 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
630 const int backdrillRadiusBIU = secondaryDrillSize.value() / 2;
632 const int holeOuterRadiusBIU = hole_outer_radius;
635 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
644 backdrillOuterRadiusBIU,
via->GetMaxError(),
648 backdrillRadiusBIU,
via->GetMaxError(),
652 backdrillOuterRadiusBIU,
via->GetMaxError(),
659 const auto tertiaryDrillSize =
via->GetTertiaryDrillSize();
661 if( tertiaryDrillSize.has_value() && tertiaryDrillSize.value() > 0 )
663 const int backdrillRadiusBIU = tertiaryDrillSize.value() / 2;
665 const int holeOuterRadiusBIU = hole_outer_radius;
668 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
678 backdrillOuterRadiusBIU,
via->GetMaxError(),
682 backdrillRadiusBIU,
via->GetMaxError(),
686 backdrillOuterRadiusBIU,
via->GetMaxError(),
705 unsigned int nTracks = trackList.size();
707 for(
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
709 const PCB_TRACK *track = trackList[trackIdx];
727 for(
PAD*
pad : footprint->Pads() )
730 if( !
pad->HasHole() )
734 double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
757 const float holeDiameterUnits =
static_cast<float>(
759 const float holeInnerRadius = holeDiameterUnits / 2.0f;
763 const auto frontMode =
pad->GetFrontPostMachining();
765 if( frontMode.has_value()
769 const float frontRadius =
pad->GetFrontPostMachiningSize() * 0.5f
772 if( frontRadius > holeInnerRadius )
787 const auto backMode =
pad->GetBackPostMachining();
789 if( backMode.has_value()
793 const float backRadius =
pad->GetBackPostMachiningSize() * 0.5f
796 if( backRadius > holeInnerRadius )
812 const VECTOR2I& secDrillSize =
pad->GetSecondaryDrillSize();
814 if( secDrillSize.
x > 0 || secDrillSize.
y > 0 )
816 const float backdrillRadius = ( secDrillSize.
x + secDrillSize.
y ) * 0.25f
820 const float holeOuterRadius = holeInnerRadius
825 if( backdrillRadius > holeOuterRadius )
847 layerHoleContainer->
Add(
861 for(
PAD*
pad : footprint->Pads() )
863 if( !
pad->HasHole() )
887 const double holeDiameter = (
pad->GetDrillSize().x +
pad->GetDrillSize().y ) / 2.0;
888 const int holeRadius =
KiROUND( holeDiameter / 2.0 );
890 const auto frontMode =
pad->GetFrontPostMachining();
892 if( frontMode.has_value()
896 const int frontRadiusBIU =
pad->GetFrontPostMachiningSize() / 2;
898 if( frontRadiusBIU > holeRadius )
903 frontRadiusBIU,
pad->GetMaxError(),
909 frontRadiusBIU,
pad->GetMaxError(),
915 const auto backMode =
pad->GetBackPostMachining();
917 if( backMode.has_value()
921 const int backRadiusBIU =
pad->GetBackPostMachiningSize() / 2;
923 if( backRadiusBIU > holeRadius )
928 backRadiusBIU,
pad->GetMaxError(),
934 backRadiusBIU,
pad->GetMaxError(),
941 const VECTOR2I& secDrillSize =
pad->GetSecondaryDrillSize();
943 if( secDrillSize.
x > 0 || secDrillSize.
y > 0 )
945 const int backdrillRadiusBIU = ( secDrillSize.
x + secDrillSize.
y ) / 4;
946 const int holeOuterRadiusBIU = holeRadius + inflate;
949 if( backdrillRadiusBIU > holeOuterRadiusBIU )
955 backdrillRadiusBIU,
pad->GetMaxError(),
976 backdrillRadiusBIU,
pad->GetMaxError(),
993 addPads( fp, layerContainer, layer );
1001 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(),
ERROR_INSIDE );
1013 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(),
ERROR_INSIDE );
1030 if( !item->IsOnLayer( layer ) )
1033 switch( item->Type() )
1067 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ), item->Type() );
1084 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, text_box->
GetMaxError(),
1094 item->TransformShapeToPolySet( *copperPolys, layer, 0, item->GetMaxError(),
ERROR_INSIDE );
1105 switch( item->Type() )
1108 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(),
ERROR_INSIDE );
1125 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->
GetMaxError(),
1138 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(),
ERROR_INSIDE );
1168 for(
const std::shared_ptr<SHAPE>& shape : dimension->
GetShapes() )
1178 wxLogTrace(
m_logTrace, wxT(
"createLayers: item type: %d not implemented" ), item->Type() );
1187 if( aStatusReporter )
1188 aStatusReporter->
Report(
_(
"Create zones" ) );
1190 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
1191 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
1197 zones.emplace_back( std::make_pair( zone, layer ) );
1198 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
1204 zone->TransformShapeToPolygon( *copperPolys, layer, 0, zone->GetMaxError(),
ERROR_INSIDE );
1210 std::atomic<size_t> nextZone( 0 );
1211 std::atomic<size_t> threadsFinished( 0 );
1213 size_t parallelThreadCount = std::min<size_t>( zones.size(),
1214 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
1216 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1218 std::thread t = std::thread( [&]()
1220 for(
size_t areaId = nextZone.fetch_add( 1 );
1221 areaId < zones.size();
1222 areaId = nextZone.fetch_add( 1 ) )
1224 ZONE* zone = zones[areaId].first;
1226 if( zone ==
nullptr )
1237 auto mut_it = layer_lock.find( layer );
1239 if( mut_it != layer_lock.end() )
1241 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
1253 while( threadsFinished < parallelThreadCount )
1254 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1296 if( aStatusReporter )
1297 aStatusReporter->
Report(
_(
"Build Tech layers" ) );
1363 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
1373 if( aStatusReporter )
1374 aStatusReporter->
Report( wxString::Format(
_(
"Build Tech layer %d" ), (
int) layer ) );
1390 if( !item->IsOnLayer( layer ) )
1393 switch( item->Type() )
1433 if( !track->IsOnLayer( layer ) )
1443 if( !
via->FlashLayer( copper_layer ) )
1447 int maskExpansion = track->GetSolderMaskExpansion();
1459 for(
PAD*
pad : footprint->Pads() )
1461 if( !
pad->IsOnLayer( layer ) )
1469 addPads( footprint, layerContainer, layer );
1480 if( zone->IsOnLayer( layer ) )
1494 if( !item->IsOnLayer( layer ) )
1497 switch( item->Type() )
1500 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(),
ERROR_INSIDE );
1517 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->
GetMaxError(),
1530 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(),
ERROR_INSIDE );
1567 if(
via->FlashLayer( layer ) && !
via->IsTented( layer ) )
1569 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1575 if( track->HasSolderMask() )
1577 track->TransformShapeToPolySet( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1591 for(
PAD*
pad : footprint->Pads() )
1593 if(
pad->IsOnLayer( layer ) )
1602 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, footprint->GetMaxError(),
ERROR_INSIDE );
1614 if( zone->IsOnLayer( layer ) )
1615 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1633 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1635 if( footprint->IsFlipped() )
1648 if( aStatusReporter )
1649 aStatusReporter->
Report(
_(
"Simplifying copper layer polygons" ) );
1653 if( aStatusReporter )
1654 aStatusReporter->
Report(
_(
"Calculating plated copper" ) );
1683 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1684 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1688 layer_id_without_F_and_B.clear();
1689 layer_id_without_F_and_B.reserve( layer_ids.size() );
1693 if( layer !=
F_Cu && layer !=
B_Cu )
1694 layer_id_without_F_and_B.push_back( layer );
1697 selected_layer_id = layer_id_without_F_and_B;
1700 if( selected_layer_id.size() > 0 )
1702 if( aStatusReporter )
1704 aStatusReporter->
Report( wxString::Format(
_(
"Simplifying %d copper layers" ),
1705 (
int) selected_layer_id.size() ) );
1708 std::atomic<size_t> nextItem( 0 );
1709 std::atomic<size_t> threadsFinished( 0 );
1711 size_t parallelThreadCount = std::min<size_t>(
1712 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1713 selected_layer_id.size() );
1715 for(
size_t ii = 0; ii < parallelThreadCount; ++ii )
1717 std::thread t = std::thread(
1718 [&nextItem, &threadsFinished, &selected_layer_id,
this]()
1720 for(
size_t i = nextItem.fetch_add( 1 );
1721 i < selected_layer_id.size();
1722 i = nextItem.fetch_add( 1 ) )
1738 while( threadsFinished < parallelThreadCount )
1739 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1744 if( aStatusReporter )
1745 aStatusReporter->
Report(
_(
"Simplify holes contours" ) );
1764 if( aStatusReporter )
1765 aStatusReporter->
Report(
_(
"Build BVH for holes and vias" ) );
1780 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole :
m_layerHoleMap )
1781 hole.second->BuildBVH();