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