KiCad PCB EDA Suite
create_layer_items.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
33 #include "board_adapter.h"
34 #include "../3d_rendering/3d_render_raytracing/shapes2D/cring2d.h"
35 #include "../3d_rendering/3d_render_raytracing/shapes2D/cfilledcircle2d.h"
36 #include "../3d_rendering/3d_render_raytracing/shapes3D/ccylinder.h"
37 
38 #include <class_board.h>
39 #include <class_module.h>
40 #include <class_pad.h>
41 #include <class_pcb_text.h>
42 #include <class_edge_mod.h>
43 #include <class_zone.h>
45 #include <trigo.h>
46 #include <vector>
47 #include <thread>
48 #include <algorithm>
49 #include <atomic>
50 
51 #ifdef PRINT_STATISTICS_3D_VIEWER
52 #include <profile.h>
53 #endif
54 
55 
57 {
58  if( !m_layers_poly.empty() )
59  {
60  for( auto& poly : m_layers_poly )
61  delete poly.second;
62 
63  m_layers_poly.clear();
64  }
65 
66  if( !m_layers_inner_holes_poly.empty() )
67  {
68  for( auto& poly : m_layers_inner_holes_poly )
69  delete poly.second;
70 
72  }
73 
74  if( !m_layers_outer_holes_poly.empty() )
75  {
76  for( auto& poly : m_layers_outer_holes_poly )
77  delete poly.second;
78 
80  }
81 
82  if( !m_layers_container2D.empty() )
83  {
84  for( auto& poly : m_layers_container2D )
85  delete poly.second;
86 
87  m_layers_container2D.clear();
88  }
89 
90  if( !m_layers_holes2D.empty() )
91  {
92  for( auto& poly : m_layers_holes2D )
93  delete poly.second;
94 
95  m_layers_holes2D.clear();
96  }
97 
106  //m_through_inner_holes_poly.RemoveAllContours();
107 
111 }
112 
113 
114 void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
115 {
116  destroyLayers();
117 
118  // Build Copper layers
119  // Based on: https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
120  // /////////////////////////////////////////////////////////////////////////
121 
122 #ifdef PRINT_STATISTICS_3D_VIEWER
123  unsigned stats_startCopperLayersTime = GetRunningMicroSecs();
124 
125  unsigned start_Time = stats_startCopperLayersTime;
126 #endif
127 
128  PCB_LAYER_ID cu_seq[MAX_CU_LAYERS];
130 
131  m_stats_nr_tracks = 0;
133  m_stats_nr_vias = 0;
135  m_stats_nr_holes = 0;
137 
138  // Prepare track list, convert in a vector. Calc statistic for the holes
139  // /////////////////////////////////////////////////////////////////////////
140  std::vector< const TRACK *> trackList;
141  trackList.clear();
142  trackList.reserve( m_board->Tracks().size() );
143 
144  for( TRACK* track : m_board->Tracks() )
145  {
146  if( !Is3DLayerEnabled( track->GetLayer() ) ) // Skip non enabled layers
147  continue;
148 
149  // Note: a TRACK holds normal segment tracks and
150  // also vias circles (that have also drill values)
151  trackList.push_back( track );
152 
153  if( track->Type() == PCB_VIA_T )
154  {
155  const VIA *via = static_cast< const VIA*>( track );
156  m_stats_nr_vias++;
158  }
159  else
160  {
162  }
163 
164  m_stats_track_med_width += track->GetWidth() * m_biuTo3Dunits;
165  }
166 
167  if( m_stats_nr_tracks )
169 
170  if( m_stats_nr_vias )
172 
173 #ifdef PRINT_STATISTICS_3D_VIEWER
174  printf( "T01: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
175  start_Time = GetRunningMicroSecs();
176 #endif
177 
178  // Prepare copper layers index and containers
179  // /////////////////////////////////////////////////////////////////////////
180  std::vector< PCB_LAYER_ID > layer_id;
181  layer_id.clear();
182  layer_id.reserve( m_copperLayersCount );
183 
184  for( unsigned i = 0; i < arrayDim( cu_seq ); ++i )
185  cu_seq[i] = ToLAYER_ID( B_Cu - i );
186 
187  for( LSEQ cu = cu_set.Seq( cu_seq, arrayDim( cu_seq ) ); cu; ++cu )
188  {
189  const PCB_LAYER_ID curr_layer_id = *cu;
190 
191  if( !Is3DLayerEnabled( curr_layer_id ) ) // Skip non enabled layers
192  continue;
193 
194  layer_id.push_back( curr_layer_id );
195 
196  CBVHCONTAINER2D *layerContainer = new CBVHCONTAINER2D;
197  m_layers_container2D[curr_layer_id] = layerContainer;
198 
201  {
202  SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
203  m_layers_poly[curr_layer_id] = layerPoly;
204  }
205  }
206 
207 #ifdef PRINT_STATISTICS_3D_VIEWER
208  printf( "T02: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
209  start_Time = GetRunningMicroSecs();
210 #endif
211 
212  if( aStatusReporter )
213  aStatusReporter->Report( _( "Create tracks and vias" ) );
214 
215  // Create tracks as objects and add it to container
216  // /////////////////////////////////////////////////////////////////////////
217  for( PCB_LAYER_ID curr_layer_id : layer_id )
218  {
219  wxASSERT( m_layers_container2D.find( curr_layer_id ) != m_layers_container2D.end() );
220 
221  CBVHCONTAINER2D *layerContainer = m_layers_container2D[curr_layer_id];
222 
223  // ADD TRACKS
224  unsigned int nTracks = trackList.size();
225 
226  for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
227  {
228  const TRACK *track = trackList[trackIdx];
229 
230  // NOTE: Vias can be on multiple layers
231  if( !track->IsOnLayer( curr_layer_id ) )
232  continue;
233 
234  // Add object item to layer container
235  createNewTrack( track, layerContainer, 0.0f );
236  }
237  }
238 
239 #ifdef PRINT_STATISTICS_3D_VIEWER
240  printf( "T03: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
241  start_Time = GetRunningMicroSecs();
242 #endif
243 
244  // Create VIAS and THTs objects and add it to holes containers
245  // /////////////////////////////////////////////////////////////////////////
246  for( PCB_LAYER_ID curr_layer_id : layer_id )
247  {
248  // ADD TRACKS
249  unsigned int nTracks = trackList.size();
250 
251  for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
252  {
253  const TRACK *track = trackList[trackIdx];
254 
255  if( !track->IsOnLayer( curr_layer_id ) )
256  continue;
257 
258  // ADD VIAS and THT
259  if( track->Type() == PCB_VIA_T )
260  {
261  const VIA* via = static_cast<const VIA*>( track );
262  const VIATYPE viatype = via->GetViaType();
263  const float holediameter = via->GetDrillValue() * BiuTo3Dunits();
264  const float thickness = GetCopperThickness3DU();
265  const float hole_inner_radius = ( holediameter / 2.0f );
266  const float ring_radius = via->GetWidth() * BiuTo3Dunits() / 2.0f;
267 
268  const SFVEC2F via_center(
269  via->GetStart().x * m_biuTo3Dunits, -via->GetStart().y * m_biuTo3Dunits );
270 
271  if( viatype != VIATYPE::THROUGH )
272  {
273 
274  // Add hole objects
275  // /////////////////////////////////////////////////////////
276 
277  CBVHCONTAINER2D *layerHoleContainer = NULL;
278 
279  // Check if the layer is already created
280  if( m_layers_holes2D.find( curr_layer_id ) == m_layers_holes2D.end() )
281  {
282  // not found, create a new container
283  layerHoleContainer = new CBVHCONTAINER2D;
284  m_layers_holes2D[curr_layer_id] = layerHoleContainer;
285  }
286  else
287  {
288  // found
289  layerHoleContainer = m_layers_holes2D[curr_layer_id];
290  }
291 
292  // Add a hole for this layer
293  layerHoleContainer->Add( new CFILLEDCIRCLE2D( via_center,
294  hole_inner_radius + thickness,
295  *track ) );
296  }
297  else if( curr_layer_id == layer_id[0] ) // it only adds once the THT holes
298  {
299  // Add through hole object
300  // /////////////////////////////////////////////////////////
301  m_through_holes_outer.Add( new CFILLEDCIRCLE2D( via_center,
302  hole_inner_radius + thickness,
303  *track ) );
305  new CFILLEDCIRCLE2D( via_center,
306  hole_inner_radius + thickness,
307  *track ) );
308 
310  {
312  new CFILLEDCIRCLE2D( via_center, ring_radius, *track ) );
314  new CFILLEDCIRCLE2D( via_center, ring_radius, *track ) );
315  }
316 
317  m_through_holes_inner.Add( new CFILLEDCIRCLE2D( via_center,
318  hole_inner_radius,
319  *track ) );
320 
321  //m_through_holes_vias_inner.Add( new CFILLEDCIRCLE2D( via_center,
322  // hole_inner_radius,
323  // *track ) );
324  }
325  }
326  }
327  }
328 
329 #ifdef PRINT_STATISTICS_3D_VIEWER
330  printf( "T04: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
331  start_Time = GetRunningMicroSecs();
332 #endif
333 
334  // Create VIAS and THTs objects and add it to holes containers
335  // /////////////////////////////////////////////////////////////////////////
336  for( PCB_LAYER_ID curr_layer_id : layer_id )
337  {
338  // ADD TRACKS
339  const unsigned int nTracks = trackList.size();
340 
341  for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
342  {
343  const TRACK *track = trackList[trackIdx];
344 
345  if( !track->IsOnLayer( curr_layer_id ) )
346  continue;
347 
348  // ADD VIAS and THT
349  if( track->Type() == PCB_VIA_T )
350  {
351  const VIA *via = static_cast< const VIA*>( track );
352  const VIATYPE viatype = via->GetViaType();
353 
354  if( viatype != VIATYPE::THROUGH )
355  {
356 
357  // Add VIA hole contourns
358  // /////////////////////////////////////////////////////////
359 
360  // Add outer holes of VIAs
361  SHAPE_POLY_SET *layerOuterHolesPoly = NULL;
362  SHAPE_POLY_SET *layerInnerHolesPoly = NULL;
363 
364  // Check if the layer is already created
365  if( m_layers_outer_holes_poly.find( curr_layer_id ) ==
367  {
368  // not found, create a new container
369  layerOuterHolesPoly = new SHAPE_POLY_SET;
370  m_layers_outer_holes_poly[curr_layer_id] = layerOuterHolesPoly;
371 
372  wxASSERT( m_layers_inner_holes_poly.find( curr_layer_id ) ==
374 
375  layerInnerHolesPoly = new SHAPE_POLY_SET;
376  m_layers_inner_holes_poly[curr_layer_id] = layerInnerHolesPoly;
377  }
378  else
379  {
380  // found
381  layerOuterHolesPoly = m_layers_outer_holes_poly[curr_layer_id];
382 
383  wxASSERT( m_layers_inner_holes_poly.find( curr_layer_id ) !=
385 
386  layerInnerHolesPoly = m_layers_inner_holes_poly[curr_layer_id];
387  }
388 
389  const int holediameter = via->GetDrillValue();
390  const int hole_outer_radius = (holediameter / 2) + GetCopperThicknessBIU();
391 
392  TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(),
393  hole_outer_radius, ARC_HIGH_DEF );
394 
395  TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(),
396  holediameter / 2, ARC_HIGH_DEF );
397  }
398  else if( curr_layer_id == layer_id[0] ) // it only adds once the THT holes
399  {
400  const int holediameter = via->GetDrillValue();
401  const int hole_outer_radius = (holediameter / 2)+ GetCopperThicknessBIU();
402  const int hole_outer_ring_radius = via->GetWidth() / 2.0f;
403 
404  // Add through hole contourns
405  // /////////////////////////////////////////////////////////
407  hole_outer_radius, ARC_HIGH_DEF );
408 
410  holediameter / 2, ARC_HIGH_DEF );
411 
412  // Add samething for vias only
413 
415  via->GetStart(), hole_outer_radius, ARC_HIGH_DEF );
417  {
419  via->GetStart(), hole_outer_ring_radius, ARC_HIGH_DEF );
420  }
421 
422  //TransformCircleToPolygon( m_through_inner_holes_vias_poly,
423  // via->GetStart(),
424  // holediameter / 2,
425  // GetNrSegmentsCircle( holediameter ) );
426  }
427  }
428  }
429  }
430 
431 #ifdef PRINT_STATISTICS_3D_VIEWER
432  printf( "T05: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
433  start_Time = GetRunningMicroSecs();
434 #endif
435 
436  // Creates outline contours of the tracks and add it to the poly of the layer
437  // /////////////////////////////////////////////////////////////////////////
440  {
441  for( PCB_LAYER_ID curr_layer_id : layer_id )
442  {
443  wxASSERT( m_layers_poly.find( curr_layer_id ) != m_layers_poly.end() );
444 
445  SHAPE_POLY_SET *layerPoly = m_layers_poly[curr_layer_id];
446 
447  // ADD TRACKS
448  unsigned int nTracks = trackList.size();
449 
450  for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
451  {
452  const TRACK *track = trackList[trackIdx];
453 
454  if( !track->IsOnLayer( curr_layer_id ) )
455  continue;
456 
457  // Add the track contour
458  track->TransformShapeWithClearanceToPolygon( *layerPoly, 0 );
459  }
460  }
461  }
462 
463 #ifdef PRINT_STATISTICS_3D_VIEWER
464  printf( "T06: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
465  start_Time = GetRunningMicroSecs();
466 #endif
467 
468  // Add holes of modules
469  // /////////////////////////////////////////////////////////////////////////
470  for( MODULE* module : m_board->Modules() )
471  {
472  for( D_PAD* pad : module->Pads() )
473  {
474  const wxSize padHole = pad->GetDrillSize();
475 
476  if( !padHole.x ) // Not drilled pad like SMD pad
477  continue;
478 
479  // The hole in the body is inflated by copper thickness,
480  // if not plated, no copper
481  const int inflate = (pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED) ?
482  GetCopperThicknessBIU() : 0;
483 
485  m_stats_hole_med_diameter += ( ( pad->GetDrillSize().x +
486  pad->GetDrillSize().y ) / 2.0f ) * m_biuTo3Dunits;
487 
488  m_through_holes_outer.Add( createNewPadDrill( pad, inflate ) );
490  {
492  }
494  }
495  }
496  if( m_stats_nr_holes )
498 
499 #ifdef PRINT_STATISTICS_3D_VIEWER
500  printf( "T07: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
501  start_Time = GetRunningMicroSecs();
502 #endif
503 
504  // Add contours of the pad holes (pads can be Circle or Segment holes)
505  // /////////////////////////////////////////////////////////////////////////
506  for( MODULE* module : m_board->Modules() )
507  {
508  for( D_PAD* pad : module->Pads() )
509  {
510  const wxSize padHole = pad->GetDrillSize();
511 
512  if( !padHole.x ) // Not drilled pad like SMD pad
513  continue;
514 
515  // The hole in the body is inflated by copper thickness.
516  const int inflate = GetCopperThicknessBIU();
517 
518  if( pad->GetAttribute () != PAD_ATTRIB_HOLE_NOT_PLATED )
519  {
520  pad->TransformHoleWithClearanceToPolygon( m_through_outer_holes_poly, inflate );
521  pad->TransformHoleWithClearanceToPolygon( m_through_inner_holes_poly, 0 );
522  }
523  else
524  {
525  // If not plated, no copper.
526  pad->TransformHoleWithClearanceToPolygon( m_through_outer_holes_poly_NPTH, inflate );
527  }
528  }
529  }
530 
531 #ifdef PRINT_STATISTICS_3D_VIEWER
532  printf( "T08: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
533  start_Time = GetRunningMicroSecs();
534 #endif
535 
536  // Add modules PADs objects to containers
537  // /////////////////////////////////////////////////////////////////////////
538  for( PCB_LAYER_ID curr_layer_id : layer_id )
539  {
540  wxASSERT( m_layers_container2D.find( curr_layer_id ) != m_layers_container2D.end() );
541 
542  CBVHCONTAINER2D *layerContainer = m_layers_container2D[curr_layer_id];
543 
544  // ADD PADS
545  for( MODULE* module : m_board->Modules() )
546  {
547  // Note: NPTH pads are not drawn on copper layers when the pad
548  // has same shape as its hole
550  layerContainer,
551  curr_layer_id,
552  0,
553  true );
554 
555  // Micro-wave modules may have items on copper layers
557  layerContainer,
558  curr_layer_id,
559  0 );
560  }
561  }
562 
563 #ifdef PRINT_STATISTICS_3D_VIEWER
564  printf( "T09: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
565  start_Time = GetRunningMicroSecs();
566 #endif
567 
568  // Add modules PADs poly contourns
569  // /////////////////////////////////////////////////////////////////////////
572  {
573  for( PCB_LAYER_ID curr_layer_id : layer_id )
574  {
575  wxASSERT( m_layers_poly.find( curr_layer_id ) != m_layers_poly.end() );
576 
577  SHAPE_POLY_SET *layerPoly = m_layers_poly[curr_layer_id];
578 
579  // ADD PADS
580  for( auto module : m_board->Modules() )
581  {
582  // Construct polys
583  // /////////////////////////////////////////////////////////////
584 
585  // Note: NPTH pads are not drawn on copper layers when the pad
586  // has same shape as its hole
587  module->TransformPadsShapesWithClearanceToPolygon( curr_layer_id,
588  *layerPoly,
589  0,
590  true );
591 
592  // Micro-wave modules may have items on copper layers
593  module->TransformGraphicTextWithClearanceToPolygonSet( curr_layer_id,
594  *layerPoly,
595  0 );
596 
597  transformGraphicModuleEdgeToPolygonSet( module, curr_layer_id, *layerPoly );
598  }
599  }
600  }
601 
602 #ifdef PRINT_STATISTICS_3D_VIEWER
603  printf( "T10: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
604  start_Time = GetRunningMicroSecs();
605 #endif
606 
607  // Add graphic item on copper layers to object containers
608  // /////////////////////////////////////////////////////////////////////////
609  for( PCB_LAYER_ID curr_layer_id : layer_id )
610  {
611  wxASSERT( m_layers_container2D.find( curr_layer_id ) != m_layers_container2D.end() );
612 
613  CBVHCONTAINER2D *layerContainer = m_layers_container2D[curr_layer_id];
614 
615  // ADD GRAPHIC ITEMS ON COPPER LAYERS (texts)
616  for( auto item : m_board->Drawings() )
617  {
618  if( !item->IsOnLayer( curr_layer_id ) )
619  continue;
620 
621  switch( item->Type() )
622  {
623  case PCB_LINE_T:
624  {
626  layerContainer,
627  curr_layer_id,
628  0 );
629  }
630  break;
631 
632  case PCB_TEXT_T:
634  layerContainer,
635  curr_layer_id,
636  0 );
637  break;
638 
639  case PCB_DIMENSION_T:
641  layerContainer,
642  curr_layer_id,
643  0 );
644  break;
645 
646  default:
647  wxLogTrace( m_logTrace,
648  wxT( "createLayers: item type: %d not implemented" ),
649  item->Type() );
650  break;
651  }
652  }
653  }
654 
655 #ifdef PRINT_STATISTICS_3D_VIEWER
656  printf( "T11: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
657  start_Time = GetRunningMicroSecs();
658 #endif
659 
660  // Add graphic item on copper layers to poly contourns
661  // /////////////////////////////////////////////////////////////////////////
664  {
665  for( PCB_LAYER_ID cur_layer_id : layer_id )
666  {
667  wxASSERT( m_layers_poly.find( cur_layer_id ) != m_layers_poly.end() );
668 
669  SHAPE_POLY_SET *layerPoly = m_layers_poly[cur_layer_id];
670 
671  // ADD GRAPHIC ITEMS ON COPPER LAYERS (texts)
672  for( BOARD_ITEM* item : m_board->Drawings() )
673  {
674  if( !item->IsOnLayer( cur_layer_id ) )
675  continue;
676 
677  switch( item->Type() )
678  {
679  case PCB_LINE_T:
680  ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly, 0 );
681  break;
682 
683  case PCB_TEXT_T:
684  ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( *layerPoly, 0 );
685  break;
686 
687  default:
688  wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
689  item->Type() );
690  break;
691  }
692  }
693  }
694  }
695 
696 #ifdef PRINT_STATISTICS_3D_VIEWER
697  printf( "T12: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
698  start_Time = GetRunningMicroSecs();
699 #endif
700 
701  if( GetFlag( FL_ZONE ) )
702  {
703  if( aStatusReporter )
704  aStatusReporter->Report( _( "Create zones" ) );
705 
706  std::vector<std::pair<const ZONE_CONTAINER*, PCB_LAYER_ID>> zones;
707 
708  for( int i = 0; i < m_board->GetAreaCount(); i++ )
709  {
710  const ZONE_CONTAINER* zone = m_board->GetArea( i );
711 
712  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
713  zones.emplace_back( std::make_pair( zone, layer ) );
714  }
715 
716  // Add zones objects
717  // /////////////////////////////////////////////////////////////////////
718  std::atomic<size_t> nextZone( 0 );
719  std::atomic<size_t> threadsFinished( 0 );
720 
721  size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
722  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
723  {
724  std::thread t = std::thread( [&]()
725  {
726  for( size_t areaId = nextZone.fetch_add( 1 );
727  areaId < zones.size();
728  areaId = nextZone.fetch_add( 1 ) )
729  {
730  const ZONE_CONTAINER* zone = zones[areaId].first;
731 
732  if( zone == nullptr )
733  break;
734 
735  PCB_LAYER_ID layer = zones[areaId].second;
736 
737  auto layerContainer = m_layers_container2D.find( layer );
738 
739  if( layerContainer != m_layers_container2D.end() )
740  AddSolidAreasShapesToContainer( zone, layerContainer->second, layer );
741  }
742 
743  threadsFinished++;
744  } );
745 
746  t.detach();
747  }
748 
749  while( threadsFinished < parallelThreadCount )
750  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
751 
752  }
753 
754 #ifdef PRINT_STATISTICS_3D_VIEWER
755  printf( "fill zones T13: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
756  start_Time = GetRunningMicroSecs();
757 #endif
758 
761  {
762  // ADD COPPER ZONES
763  for( ZONE_CONTAINER* zone : m_board->Zones() )
764  {
765  if( zone == nullptr )
766  break;
767 
768  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
769  {
770  auto layerContainer = m_layers_poly.find( layer );
771 
772  if( layerContainer != m_layers_poly.end() )
773  zone->TransformSolidAreasShapesToPolygonSet( layer, *layerContainer->second );
774  }
775  }
776  }
777 
778 #ifdef PRINT_STATISTICS_3D_VIEWER
779  printf( "T14: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
780  start_Time = GetRunningMicroSecs();
781 #endif
782 
783  // Simplify layer polygons
784  // /////////////////////////////////////////////////////////////////////////
785 
786  if( aStatusReporter )
787  aStatusReporter->Report( _( "Simplifying copper layers polygons" ) );
788 
791  {
792  std::atomic<size_t> nextItem( 0 );
793  std::atomic<size_t> threadsFinished( 0 );
794 
795  size_t parallelThreadCount = std::min<size_t>(
796  std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
797  layer_id.size() );
798  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
799  {
800  std::thread t = std::thread( [&nextItem, &threadsFinished, &layer_id, this]()
801  {
802  for( size_t i = nextItem.fetch_add( 1 );
803  i < layer_id.size();
804  i = nextItem.fetch_add( 1 ) )
805  {
806  auto layerPoly = m_layers_poly.find( layer_id[i] );
807 
808  if( layerPoly != m_layers_poly.end() )
809  // This will make a union of all added contours
810  layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
811  }
812 
813  threadsFinished++;
814  } );
815 
816  t.detach();
817  }
818 
819  while( threadsFinished < parallelThreadCount )
820  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
821  }
822 
823 #ifdef PRINT_STATISTICS_3D_VIEWER
824  printf( "T15: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
825  start_Time = GetRunningMicroSecs();
826 #endif
827 
828  // Simplify holes polygon contours
829  // /////////////////////////////////////////////////////////////////////////
830  if( aStatusReporter )
831  aStatusReporter->Report( _( "Simplify holes contours" ) );
832 
833  for( PCB_LAYER_ID layer : layer_id )
834  {
835  if( m_layers_outer_holes_poly.find( layer ) != m_layers_outer_holes_poly.end() )
836  {
837  // found
838  SHAPE_POLY_SET *polyLayer = m_layers_outer_holes_poly[layer];
839  polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
840 
841  wxASSERT( m_layers_inner_holes_poly.find( layer ) != m_layers_inner_holes_poly.end() );
842 
843  polyLayer = m_layers_inner_holes_poly[layer];
844  polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
845  }
846  }
847 
848 #ifdef PRINT_STATISTICS_3D_VIEWER
849  printf( "T16: %.3f ms\n", (float)( GetRunningMicroSecs() - start_Time ) / 1e3 );
850 #endif
851  // End Build Copper layers
852 
853 
854  // This will make a union of all added contourns
860  //m_through_inner_holes_vias_poly.Simplify( SHAPE_POLY_SET::PM_FAST ); // Not in use
861 
862 #ifdef PRINT_STATISTICS_3D_VIEWER
863  unsigned stats_endCopperLayersTime = GetRunningMicroSecs();
864 #endif
865 
866  // Build Tech layers
867  // Based on: https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
868  // /////////////////////////////////////////////////////////////////////////
869 #ifdef PRINT_STATISTICS_3D_VIEWER
870  unsigned stats_startTechLayersTime = GetRunningMicroSecs();
871 #endif
872 
873  if( aStatusReporter )
874  aStatusReporter->Report( _( "Build Tech layers" ) );
875 
876  // draw graphic items, on technical layers
877  static const PCB_LAYER_ID teckLayerList[] = {
878  B_Adhes,
879  F_Adhes,
880  B_Paste,
881  F_Paste,
882  B_SilkS,
883  F_SilkS,
884  B_Mask,
885  F_Mask,
886 
887  // Aux Layers
888  Dwgs_User,
889  Cmts_User,
890  Eco1_User,
891  Eco2_User,
892  Edge_Cuts,
893  Margin
894  };
895 
896  // User layers are not drawn here, only technical layers
897 
898  for( LSEQ seq = LSET::AllNonCuMask().Seq( teckLayerList, arrayDim( teckLayerList ) );
899  seq;
900  ++seq )
901  {
902  const PCB_LAYER_ID curr_layer_id = *seq;
903 
904  if( !Is3DLayerEnabled( curr_layer_id ) )
905  continue;
906 
907  CBVHCONTAINER2D *layerContainer = new CBVHCONTAINER2D;
908  m_layers_container2D[curr_layer_id] = layerContainer;
909 
910  SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
911  m_layers_poly[curr_layer_id] = layerPoly;
912 
913  // Add drawing objects
914  // /////////////////////////////////////////////////////////////////////
915  for( BOARD_ITEM* item : m_board->Drawings() )
916  {
917  if( !item->IsOnLayer( curr_layer_id ) )
918  continue;
919 
920  switch( item->Type() )
921  {
922  case PCB_LINE_T:
924  layerContainer,
925  curr_layer_id,
926  0 );
927  break;
928 
929  case PCB_TEXT_T:
931  layerContainer,
932  curr_layer_id,
933  0 );
934  break;
935 
936  case PCB_DIMENSION_T:
938  layerContainer,
939  curr_layer_id,
940  0 );
941  break;
942 
943  default:
944  break;
945  }
946  }
947 
948 
949  // Add drawing contours
950  // /////////////////////////////////////////////////////////////////////
951  for( BOARD_ITEM* item : m_board->Drawings() )
952  {
953  if( !item->IsOnLayer( curr_layer_id ) )
954  continue;
955 
956  switch( item->Type() )
957  {
958  case PCB_LINE_T:
959  ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( *layerPoly, 0 );
960  break;
961 
962  case PCB_TEXT_T:
963  ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( *layerPoly, 0 );
964  break;
965 
966  default:
967  break;
968  }
969  }
970 
971 
972  // Add modules tech layers - objects
973  // /////////////////////////////////////////////////////////////////////
974  for( MODULE* module : m_board->Modules() )
975  {
976  if( (curr_layer_id == F_SilkS) || (curr_layer_id == B_SilkS) )
977  {
978  int linewidth = g_DrawDefaultLineThickness;
979 
980  for( D_PAD* pad : module->Pads() )
981  {
982  if( !pad->IsOnLayer( curr_layer_id ) )
983  continue;
984 
985  buildPadShapeThickOutlineAsSegments( pad, layerContainer, linewidth );
986  }
987  }
988  else
989  {
991  module, layerContainer, curr_layer_id, 0, false );
992  }
993 
994  AddGraphicsShapesWithClearanceToContainer( module, layerContainer, curr_layer_id, 0 );
995  }
996 
997 
998  // Add modules tech layers - contours
999  // /////////////////////////////////////////////////////////////////////
1000  for( MODULE* module : m_board->Modules() )
1001  {
1002  if( (curr_layer_id == F_SilkS) || (curr_layer_id == B_SilkS) )
1003  {
1004  const int linewidth = g_DrawDefaultLineThickness;
1005 
1006  for( D_PAD* pad : module->Pads() )
1007  {
1008  if( !pad->IsOnLayer( curr_layer_id ) )
1009  continue;
1010 
1011  buildPadShapeThickOutlineAsPolygon( pad, *layerPoly, linewidth );
1012  }
1013  }
1014  else
1015  {
1016  module->TransformPadsShapesWithClearanceToPolygon( curr_layer_id, *layerPoly, 0,
1017  false );
1018  }
1019 
1020  // On tech layers, use a poor circle approximation, only for texts (stroke font)
1021  module->TransformGraphicTextWithClearanceToPolygonSet( curr_layer_id, *layerPoly, 0 );
1022 
1023  // Add the remaining things with dynamic seg count for circles
1024  transformGraphicModuleEdgeToPolygonSet( module, curr_layer_id, *layerPoly );
1025  }
1026 
1027 
1028  // Draw non copper zones
1029  // /////////////////////////////////////////////////////////////////////
1030  if( GetFlag( FL_ZONE ) )
1031  {
1032  for( int ii = 0; ii < m_board->GetAreaCount(); ++ii )
1033  {
1034  ZONE_CONTAINER* zone = m_board->GetArea( ii );
1035 
1036  if( !zone->IsOnLayer( curr_layer_id ) )
1037  continue;
1038 
1039  AddSolidAreasShapesToContainer( zone, layerContainer, curr_layer_id );
1040  }
1041 
1042  for( int ii = 0; ii < m_board->GetAreaCount(); ++ii )
1043  {
1044  ZONE_CONTAINER* zone = m_board->GetArea( ii );
1045 
1046  if( !zone->IsOnLayer( curr_layer_id ) )
1047  continue;
1048 
1049  zone->TransformSolidAreasShapesToPolygonSet( curr_layer_id, *layerPoly );
1050  }
1051  }
1052 
1053  // This will make a union of all added contours
1054  layerPoly->Simplify( SHAPE_POLY_SET::PM_FAST );
1055  }
1056  // End Build Tech layers
1057 
1058 #ifdef PRINT_STATISTICS_3D_VIEWER
1059  unsigned stats_endTechLayersTime = GetRunningMicroSecs();
1060 #endif
1061 
1062 
1063  // Build BVH for holes and vias
1064  // /////////////////////////////////////////////////////////////////////////
1065 
1066 #ifdef PRINT_STATISTICS_3D_VIEWER
1067  unsigned stats_startHolesBVHTime = GetRunningMicroSecs();
1068 #endif
1069  if( aStatusReporter )
1070  aStatusReporter->Report( _( "Build BVH for holes and vias" ) );
1071 
1075 
1076  if( !m_layers_holes2D.empty() )
1077  {
1078  for( auto& hole : m_layers_holes2D)
1079  hole.second->BuildBVH();
1080  }
1081 
1082  // We only need the Solder mask to initialize the BVH
1083  // because..?
1085  m_layers_container2D[B_Mask]->BuildBVH();
1086 
1088  m_layers_container2D[F_Mask]->BuildBVH();
1089 
1090 #ifdef PRINT_STATISTICS_3D_VIEWER
1091  unsigned stats_endHolesBVHTime = GetRunningMicroSecs();
1092 
1093  printf( "BOARD_ADAPTER::createLayers times\n" );
1094  printf( " Copper Layers: %.3f ms\n",
1095  (float)( stats_endCopperLayersTime - stats_startCopperLayersTime ) / 1e3 );
1096  printf( " Holes BVH creation: %.3f ms\n",
1097  (float)( stats_endHolesBVHTime - stats_startHolesBVHTime ) / 1e3 );
1098  printf( " Tech Layers: %.3f ms\n",
1099  (float)( stats_endTechLayersTime - stats_startTechLayersTime ) / 1e3 );
1100  printf( "Statistics:\n" );
1101  printf( " m_stats_nr_tracks %u\n", m_stats_nr_tracks );
1102  printf( " m_stats_nr_vias %u\n", m_stats_nr_vias );
1103  printf( " m_stats_nr_holes %u\n", m_stats_nr_holes );
1104  printf( " m_stats_via_med_hole_diameter (3DU) %f\n", m_stats_via_med_hole_diameter );
1105  printf( " m_stats_hole_med_diameter (3DU) %f\n", m_stats_hole_med_diameter );
1106  printf( " m_calc_seg_min_factor3DU (3DU) %f\n", m_calc_seg_min_factor3DU );
1107  printf( " m_calc_seg_max_factor3DU (3DU) %f\n", m_calc_seg_max_factor3DU );
1108 #endif
1109 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:712
double BiuTo3Dunits() const noexcept
BiuTo3Dunits - Board integer units To 3D units.
bool GetFlag(DISPLAY3D_FLG aFlag) const
GetFlag - get a configuration status of a flag.
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
TEXTE_PCB class definition.
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
SHAPE_POLY_SET m_through_outer_holes_poly_NPTH
It contains polygon contours for (just) non plated through holes (outer cylinder)
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
MAP_POLY m_layers_outer_holes_poly
It contains polygon contours for holes of each layer (outer holes)
const wxPoint & GetStart() const
Definition: class_track.h:116
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: class_zone.cpp:305
CBVHCONTAINER2D m_through_holes_inner
It contains the list of throughHoles of the board, the radius is the inner hole.
void AddGraphicsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue)
MAP_POLY m_layers_inner_holes_poly
It contains polygon contours for holes of each layer (inner holes)
static LSET AllNonCuMask()
Function AllNonCuMask returns a mask holding all layer minus CU layers.
Definition: lset.cpp:735
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the track shape to a closed polygon Used in fil...
float GetCopperThickness3DU() const noexcept
GetCopperThickness3DU - Get the current copper layer thickness.
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
SHAPE_POLY_SET m_through_outer_ring_holes_vias_poly
It contains polygon contours for through holes vias (outer annular ring)
unsigned int m_stats_nr_holes
number of holes in the board
CBVHCONTAINER2D m_through_holes_outer_ring
It contains the list of throughHoles of the board, the radius of the hole is inflated with the annula...
REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
unsigned int m_stats_nr_vias
Nr of vias.
SHAPE_POLY_SET m_through_inner_holes_poly
It contains polygon contours for through holes (inner cylinder)
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Function Seq returns an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:377
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
void buildPadShapeThickOutlineAsSegments(const D_PAD *aPad, CGENERICCONTAINER2D *aDstContainer, int aWidth)
void TransformSolidAreasShapesToPolygonSet(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aCornerBuffer, int aError=ARC_HIGH_DEF) const
Function TransformSolidAreasShapesToPolygonSet Convert solid areas full shapes to polygon set (the fu...
void AddShapeWithClearanceToContainer(const TEXTE_PCB *aTextPCB, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aClearanceValue)
virtual LSET GetLayerSet() const override
Function GetLayerSet returns a std::bitset of all layers on which the item physically resides.
Definition: class_zone.cpp:288
RENDER_ENGINE m_render_engine
SHAPE_POLY_SET m_through_inner_holes_vias_poly
It contains polygon contours for through holes vias (inner cylinder)
PCB_LAYER_ID
A quick note on layer IDs:
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:934
LSET is a set of PCB_LAYER_IDs.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Function IsOnLayer tests to see if this object is on the given layer.
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
#define NULL
MAP_CONTAINER_2D m_layers_holes2D
It contains the holes per each layer.
void AddPadsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue, bool aSkipNPTHPadsWihNoCopper)
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
MODULES & Modules()
Definition: class_board.h:266
int GetCopperThicknessBIU() const noexcept
GetCopperThicknessBIU - Get the current copper layer thickness.
SHAPE_POLY_SET.
VIATYPE
Definition: class_track.h:68
int g_DrawDefaultLineThickness
Default line thickness in internal units used to draw or plot items using a default thickness line va...
SHAPE_POLY_SET m_through_outer_holes_vias_poly
It contains polygon contours for through holes vias (outer cylinder)
float m_stats_track_med_width
Track average width.
float m_calc_seg_max_factor3DU
max factor used for cicle segment approximation calculation
double m_biuTo3Dunits
Normalization scale to convert board internal units to 3D units to normalize 3D units between -1....
bool Is3DLayerEnabled(PCB_LAYER_ID aLayer) const
Is3DLayerEnabled - Check if a layer is enabled.
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
CBVHCONTAINER2D m_through_holes_vias_outer_ring
It contains the list of throughHoles vias of the board, the radius of the hole is inflated with the a...
void buildPadShapeThickOutlineAsPolygon(const D_PAD *aPad, SHAPE_POLY_SET &aCornerBuffer, int aWidth) const
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:100
void createLayers(REPORTER *aStatusReporter)
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Pad object description.
MAP_POLY m_layers_poly
It contains polygon contours for each layer.
CBVHCONTAINER2D m_through_holes_vias_outer
It contains the list of throughHoles vias of the board, the radius of the hole is inflated with the c...
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:160
CBVHCONTAINER2D m_through_holes_outer
It contains the list of throughHoles of the board, the radius of the hole is inflated with the copper...
void transformGraphicModuleEdgeToPolygonSet(const MODULE *aModule, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aCornerBuffer) const
void Add(COBJECT2D *aObject)
Definition: ccontainer2d.h:52
ZONE_CONTAINERS & Zones()
Definition: class_board.h:280
SHAPE_POLY_SET m_through_outer_holes_poly
It contains polygon contours for through holes (outer cylinder)
int GetWidth() const
Definition: class_track.h:110
CBVHCONTAINER2D m_through_holes_vias_inner
It contains the list of throughHoles vias of the board, the radius of the hole.
#define _(s)
Definition: 3d_actions.cpp:33
unsigned GetRunningMicroSecs()
Function GetRunningMicroSecs An alternate way to calculate an elapset time (in microsecondes) to clas...
unsigned int m_copperLayersCount
Number of copper layers actually used by the board.
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
void TransformCircleToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCenter, int aRadius, int aError)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines.
VIATYPE GetViaType() const
Definition: class_track.h:374
void AddSolidAreasShapesToContainer(const ZONE_CONTAINER *aZoneContainer, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId)
COBJECT2D * createNewPadDrill(const D_PAD *aPad, int aInflateValue)
float m_stats_via_med_hole_diameter
Computed medium diameter of the via holes in 3D units.
void createNewTrack(const TRACK *aTrack, CGENERICCONTAINER2D *aDstContainer, int aClearanceValue)
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
float m_stats_hole_med_diameter
Computed medium diameter of the holes in 3D units.
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:899
MAP_CONTAINER_2D m_layers_container2D
It contains the 2d elements of each layer.
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
float m_calc_seg_min_factor3DU
min factor used for cicle segment approximation calculation
DRAWINGS & Drawings()
Definition: class_board.h:275
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:849
unsigned int m_stats_nr_tracks
Number of tracks in the board.
DIMENSION.
TRACKS & Tracks()
Definition: class_board.h:257
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193