200#ifdef PRINT_STATISTICS_3D_VIEWER 
  203    int64_t start_Time = stats_startCopperLayersTime;
 
  221    std::vector<const PCB_TRACK*> trackList;
 
  223    trackList.reserve( 
m_board->Tracks().size() );
 
  235        trackList.push_back( track );
 
  257    std::vector<PCB_LAYER_ID> layer_ids;
 
  266        layer_ids.push_back( layer );
 
  293    if( aStatusReporter )
 
  294        aStatusReporter->
Report( 
_( 
"Create tracks and vias" ) );
 
  303        for( 
const PCB_TRACK* track : trackList )
 
  306            if( !track->IsOnLayer( layer ) )
 
  322        unsigned int nTracks = trackList.size();
 
  324        for( 
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
 
  326            const PCB_TRACK *track = trackList[trackIdx];
 
  341                const float    thickness         = 
static_cast<float>( plating / 2.0f );
 
  342                const float    hole_inner_radius = 
static_cast<float>( holediameter / 2.0f );
 
  343                const float    ring_radius       = 
static_cast<float>( viasize / 2.0f );
 
  370                else if( layer == layer_ids[0] ) 
 
  379                    if( hole_inner_radius > 0.0 )
 
  401        const unsigned int nTracks = trackList.size();
 
  403        for( 
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
 
  405            const PCB_TRACK *track = trackList[trackIdx];
 
  446                    const int holediameter = 
via->GetDrillValue();
 
  455                else if( layer == layer_ids[0] ) 
 
  457                    const int holediameter = 
via->GetDrillValue();
 
  459                    const int hole_outer_ring_radius = 
KiROUND( 
via->GetWidth( layer ) / 2.0 );
 
  489            unsigned int nTracks = trackList.size();
 
  491            for( 
unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
 
  493                const PCB_TRACK *track = trackList[trackIdx];
 
  511        for( 
PAD* 
pad : footprint->Pads() )
 
  514            if( !
pad->HasHole() )
 
  518            double holeDiameter = ( 
pad->GetDrillSize().x + 
pad->GetDrillSize().y ) / 2.0;
 
  548        for( 
PAD* 
pad : footprint->Pads() )
 
  550            if( !
pad->HasHole() )
 
  583            addPads( fp, layerContainer, layer );
 
  591                fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), 
ERROR_INSIDE );
 
  603                fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), 
ERROR_INSIDE );
 
  620            if( !item->IsOnLayer( layer ) )
 
  623            switch( item->Type() )
 
  657                wxLogTrace( 
m_logTrace, wxT( 
"createLayers: item type: %d not implemented" ), item->Type() );
 
  674                    text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, text_box->
GetMaxError(),
 
  684                    item->TransformShapeToPolySet( *copperPolys, layer, 0, item->GetMaxError(), 
ERROR_INSIDE );
 
  695                switch( item->Type() )
 
  698                    item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), 
ERROR_INSIDE );
 
  715                        textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->
GetMaxError(),
 
  728                        cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), 
ERROR_INSIDE );
 
  758                    for( 
const std::shared_ptr<SHAPE>& shape : dimension->
GetShapes() )
 
  768                    wxLogTrace( 
m_logTrace, wxT( 
"createLayers: item type: %d not implemented" ), item->Type() );
 
  777        if( aStatusReporter )
 
  778            aStatusReporter->
Report( 
_( 
"Create zones" ) );
 
  780        std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
 
  781        std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
 
  787                zones.emplace_back( std::make_pair( zone, layer ) );
 
  788                layer_lock.emplace( layer, std::make_unique<std::mutex>() );
 
  794                    zone->TransformShapeToPolygon( *copperPolys, layer, 0, zone->GetMaxError(), 
ERROR_INSIDE );
 
  800        std::atomic<size_t> nextZone( 0 );
 
  801        std::atomic<size_t> threadsFinished( 0 );
 
  803        size_t parallelThreadCount = std::min<size_t>( zones.size(),
 
  804                std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
 
  806        for( 
size_t ii = 0; ii < parallelThreadCount; ++ii )
 
  808            std::thread t = std::thread( [&]()
 
  810                for( 
size_t areaId = nextZone.fetch_add( 1 );
 
  811                            areaId < zones.size();
 
  812                            areaId = nextZone.fetch_add( 1 ) )
 
  814                    ZONE* zone = zones[areaId].first;
 
  816                    if( zone == 
nullptr )
 
  827                        auto mut_it = layer_lock.find( layer );
 
  829                        if( mut_it != layer_lock.end() )
 
  831                            std::lock_guard< std::mutex > lock( *( mut_it->second ) );
 
  843        while( threadsFinished < parallelThreadCount )
 
  844            std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
 
  857    if( aStatusReporter )
 
  858        aStatusReporter->
Report( 
_( 
"Build Tech layers" ) );
 
  924    std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
 
  934        if( aStatusReporter )
 
  935            aStatusReporter->
Report( wxString::Format( 
_( 
"Build Tech layer %d" ), (
int) layer ) );
 
  951                if( !item->IsOnLayer( layer ) )
 
  954                switch( item->Type() )
 
  994                    if( !track->IsOnLayer( layer ) )
 
 1004                        if( !
via->FlashLayer( copper_layer ) )
 
 1008                    int maskExpansion = track->GetSolderMaskExpansion();
 
 1020                    for( 
PAD* 
pad : footprint->Pads() )
 
 1022                        if( !
pad->IsOnLayer( layer ) )
 
 1030                    addPads( footprint, layerContainer, layer );
 
 1041                    if( zone->IsOnLayer( layer ) )
 
 1055                if( !item->IsOnLayer( layer ) )
 
 1058                switch( item->Type() )
 
 1061                    item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), 
ERROR_INSIDE );
 
 1078                        textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->
GetMaxError(),
 
 1091                        cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), 
ERROR_INSIDE );
 
 1128                        if( 
via->FlashLayer( layer ) && !
via->IsTented( layer ) )
 
 1130                            track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, track->GetMaxError(),
 
 1136                        if( track->HasSolderMask() )
 
 1138                            track->TransformShapeToPolySet( *layerPoly, layer, maskExpansion, track->GetMaxError(),
 
 1152                    for( 
PAD* 
pad : footprint->Pads() )
 
 1154                        if( 
pad->IsOnLayer( layer ) )
 
 1163                    footprint->TransformPadsToPolySet( *layerPoly, layer, 0, footprint->GetMaxError(), 
ERROR_INSIDE );
 
 1175                    if( zone->IsOnLayer( layer ) )
 
 1176                        zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
 
 1194            if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
 
 1196                if( footprint->IsFlipped() )
 
 1209    if( aStatusReporter )
 
 1210        aStatusReporter->
Report( 
_( 
"Simplifying copper layer polygons" ) );
 
 1214        if( aStatusReporter )
 
 1215            aStatusReporter->
Report( 
_( 
"Calculating plated copper" ) );
 
 1244        std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
 
 1245        std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
 
 1249            layer_id_without_F_and_B.clear();
 
 1250            layer_id_without_F_and_B.reserve( layer_ids.size() );
 
 1254                if( layer != 
F_Cu && layer != 
B_Cu )
 
 1255                    layer_id_without_F_and_B.push_back( layer );
 
 1258            selected_layer_id = layer_id_without_F_and_B;
 
 1261        if( selected_layer_id.size() > 0 )
 
 1263            if( aStatusReporter )
 
 1265                aStatusReporter->
Report( wxString::Format( 
_( 
"Simplifying %d copper layers" ),
 
 1266                                                           (
int) selected_layer_id.size() ) );
 
 1269            std::atomic<size_t> nextItem( 0 );
 
 1270            std::atomic<size_t> threadsFinished( 0 );
 
 1272            size_t parallelThreadCount = std::min<size_t>(
 
 1273                    std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
 
 1274                    selected_layer_id.size() );
 
 1276            for( 
size_t ii = 0; ii < parallelThreadCount; ++ii )
 
 1278                std::thread t = std::thread(
 
 1279                        [&nextItem, &threadsFinished, &selected_layer_id, 
this]()
 
 1281                            for( 
size_t i = nextItem.fetch_add( 1 );
 
 1282                                        i < selected_layer_id.size();
 
 1283                                        i = nextItem.fetch_add( 1 ) )
 
 1299            while( threadsFinished < parallelThreadCount )
 
 1300                std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
 
 1305    if( aStatusReporter )
 
 1306        aStatusReporter->
Report( 
_( 
"Simplify holes contours" ) );
 
 1325    if( aStatusReporter )
 
 1326        aStatusReporter->
Report( 
_( 
"Build BVH for holes and vias" ) );
 
 1334        for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : 
m_layerHoleMap )
 
 1335            hole.second->BuildBVH();