KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include "board_adapter.h"
27#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
30#include <board.h>
31#include <layer_range.h>
32#include <lset.h>
34#include <trigo.h>
35#include <vector>
36#include <thread>
37#include <algorithm>
38#include <atomic>
39#include <wx/log.h>
40
41#ifdef PRINT_STATISTICS_3D_VIEWER
42#include <core/profile.h>
43#endif
44
45/*
46 * This is used to draw pad outlines on silk layers.
47 */
48void buildPadOutlineAsPolygon( const PAD* aPad, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aBuffer,
49 int aWidth, int aMaxError, ERROR_LOC aErrorLoc )
50{
51 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
52 {
53 TransformRingToPolygon( aBuffer, aPad->ShapePos( aLayer ), aPad->GetSize( aLayer ).x / 2,
54 aWidth, aMaxError, aErrorLoc );
55 }
56 else
57 {
58 // For other shapes, add outlines as thick segments in polygon buffer
59 const SHAPE_LINE_CHAIN& path = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE )->COutline( 0 );
60
61 for( int ii = 0; ii < path.PointCount(); ++ii )
62 {
63 const VECTOR2I& a = path.CPoint( ii );
64 const VECTOR2I& b = path.CPoint( ii + 1 );
65
66 TransformOvalToPolygon( aBuffer, a, b, aWidth, aMaxError, aErrorLoc );
67 }
68 }
69}
70
71
72void transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
73 SHAPE_POLY_SET& aBuffer, int aMaxError, ERROR_LOC aErrorLoc )
74{
75 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
76 {
77 if( item->Type() == PCB_SHAPE_T || BaseType( item->Type() ) == PCB_DIMENSION_T )
78 {
79 if( item->GetLayer() == aLayer )
80 item->TransformShapeToPolySet( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
81 }
82 }
83}
84
85
86void transformFPTextToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
87 const std::bitset<LAYER_3D_END>& aFlags, SHAPE_POLY_SET& aBuffer,
88 int aMaxError, ERROR_LOC aErrorLoc )
89{
90 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
91 {
92 if( item->GetLayer() != aLayer )
93 continue;
94
95 if( item->Type() == PCB_TEXT_T )
96 {
97 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
98
99 if( !aFlags.test( LAYER_FP_TEXT ) )
100 continue;
101
102 if( text->GetText() == wxT( "${REFERENCE}" ) && !aFlags.test( LAYER_FP_REFERENCES ) )
103 continue;
104
105 if( text->GetText() == wxT( "${VALUE}" ) && !aFlags.test( LAYER_FP_VALUES ) )
106 continue;
107
108 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer )
109 text->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
110 }
111
112 if( item->Type() == PCB_TEXTBOX_T )
113 {
114 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
115
116 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer )
117 {
118 // border
119 if( textbox->IsBorderEnabled() )
120 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
121
122 // text
123 textbox->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
124 }
125 }
126 }
127
128 for( const PCB_FIELD* field : aFootprint->GetFields() )
129 {
130 if( !aFlags.test( LAYER_FP_TEXT ) )
131 continue;
132
133 if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) )
134 continue;
135
136 if( field->IsValue() && !aFlags.test( LAYER_FP_VALUES ) )
137 continue;
138
139 if( field->GetLayer() == aLayer && field->IsVisible() )
140 field->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
141 }
142}
143
144
146{
147#define DELETE_AND_FREE( ptr ) \
148 { \
149 delete ptr; \
150 ptr = nullptr; \
151 } \
152
153#define DELETE_AND_FREE_MAP( map ) \
154 { \
155 for( auto& [ layer, poly ] : map ) \
156 delete poly; \
157 \
158 map.clear(); \
159 }
160
162
165
168
173
176
181
182 m_TH_ODs.Clear();
183 m_TH_IDs.Clear();
186}
187
188
189void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
190{
192
193 // Build Copper layers
194 // Based on:
195 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
196
197#ifdef PRINT_STATISTICS_3D_VIEWER
198 int64_t stats_startCopperLayersTime = GetRunningMicroSecs();
199
200 int64_t start_Time = stats_startCopperLayersTime;
201#endif
202
204
205 std::bitset<LAYER_3D_END> visibilityFlags = GetVisibleLayers();
206
207 m_trackCount = 0;
209 m_viaCount = 0;
211 m_holeCount = 0;
213
214 if( !m_board )
215 return;
216
217 // Prepare track list, convert in a vector. Calc statistic for the holes
218 std::vector<const PCB_TRACK*> trackList;
219 trackList.clear();
220 trackList.reserve( m_board->Tracks().size() );
221
222 for( PCB_TRACK* track : m_board->Tracks() )
223 {
224 // Skip tracks (not vias theyt are on more than one layer ) on disabled layers
225 if( track->Type() != PCB_VIA_T && !Is3dLayerEnabled( track->GetLayer(), visibilityFlags ) )
226 {
227 continue;
228 }
229
230 // Note: a PCB_TRACK holds normal segment tracks and also vias circles (that have also
231 // drill values)
232 trackList.push_back( track );
233
234 if( track->Type() == PCB_VIA_T )
235 {
236 const PCB_VIA *via = static_cast< const PCB_VIA*>( track );
237 m_viaCount++;
238 m_averageViaHoleDiameter += static_cast<float>( via->GetDrillValue() * m_biuTo3Dunits );
239 }
240 else
241 {
242 m_trackCount++;
243 m_averageTrackWidth += static_cast<float>( track->GetWidth() * m_biuTo3Dunits );
244 }
245 }
246
247 if( m_trackCount )
249
250 if( m_viaCount )
252
253 // Prepare copper layers index and containers
254 std::vector<PCB_LAYER_ID> layer_ids;
255 layer_ids.clear();
256 layer_ids.reserve( m_copperLayersCount );
257
259 {
260 if( !Is3dLayerEnabled( layer, visibilityFlags ) ) // Skip non enabled layers
261 continue;
262
263 layer_ids.push_back( layer );
264
265 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
266 m_layerMap[layer] = layerContainer;
267
268 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
269 {
270 SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
271 m_layers_poly[layer] = layerPoly;
272 }
273 }
274
275 if( cfg.DifferentiatePlatedCopper() )
276 {
279
282 }
283
284 if( cfg.show_off_board_silk )
285 {
288 }
289
290 if( aStatusReporter )
291 aStatusReporter->Report( _( "Create tracks and vias" ) );
292
293 // Create tracks as objects and add it to container
294 for( PCB_LAYER_ID layer : layer_ids )
295 {
296 wxASSERT( m_layerMap.contains( layer ) );
297
298 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
299
300 for( const PCB_TRACK* track : trackList )
301 {
302 // NOTE: Vias can be on multiple layers
303 if( !track->IsOnLayer( layer ) )
304 continue;
305
306 // Skip vias annulus when not flashed on this layer
307 if( track->Type() == PCB_VIA_T && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
308 continue;
309
310 // Add object item to layer container
311 createTrackWithMargin( track, layerContainer, layer );
312 }
313 }
314
315 // Create VIAS and THTs objects and add it to holes containers
316 for( PCB_LAYER_ID layer : layer_ids )
317 {
318 // ADD TRACKS
319 unsigned int nTracks = trackList.size();
320
321 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
322 {
323 const PCB_TRACK *track = trackList[trackIdx];
324
325 if( !track->IsOnLayer( layer ) )
326 continue;
327
328 // ADD VIAS and THT
329 if( track->Type() == PCB_VIA_T )
330 {
331 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
332 const VIATYPE viatype = via->GetViaType();
333 const double holediameter = via->GetDrillValue() * BiuTo3dUnits();
334 const double viasize = via->GetWidth( layer ) * BiuTo3dUnits();
335 const double plating = GetHolePlatingThickness() * BiuTo3dUnits();
336
337 // holes and layer copper extend half info cylinder wall to hide transition
338 const float thickness = static_cast<float>( plating / 2.0f );
339 const float hole_inner_radius = static_cast<float>( holediameter / 2.0f );
340 const float ring_radius = static_cast<float>( viasize / 2.0f );
341
342 const SFVEC2F via_center( via->GetStart().x * m_biuTo3Dunits,
343 -via->GetStart().y * m_biuTo3Dunits );
344
345 if( viatype != VIATYPE::THROUGH )
346 {
347 // Add hole objects
348 BVH_CONTAINER_2D *layerHoleContainer = nullptr;
349
350 // Check if the layer is already created
351 if( !m_layerHoleMap.contains( layer ) )
352 {
353 // not found, create a new container
354 layerHoleContainer = new BVH_CONTAINER_2D;
355 m_layerHoleMap[layer] = layerHoleContainer;
356 }
357 else
358 {
359 // found
360 layerHoleContainer = m_layerHoleMap[layer];
361 }
362
363 // Add a hole for this layer
364 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness,
365 *track ) );
366 }
367 else if( layer == layer_ids[0] ) // it only adds once the THT holes
368 {
369 // Add through hole object
370 m_TH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
371 m_viaTH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
372
373 if( cfg.clip_silk_on_via_annuli && ring_radius > 0.0 )
374 m_viaAnnuli.Add( new FILLED_CIRCLE_2D( via_center, ring_radius, *track ) );
375
376 if( hole_inner_radius > 0.0 )
377 m_TH_IDs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius, *track ) );
378 }
379 }
380
381 if( cfg.DifferentiatePlatedCopper() && layer == F_Cu )
382 {
384 ERROR_INSIDE );
385 }
386 else if( cfg.DifferentiatePlatedCopper() && layer == B_Cu )
387 {
389 ERROR_INSIDE );
390 }
391 }
392 }
393
394 // Create VIAS and THTs objects and add it to holes containers
395 for( PCB_LAYER_ID layer : layer_ids )
396 {
397 // ADD TRACKS
398 const unsigned int nTracks = trackList.size();
399
400 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
401 {
402 const PCB_TRACK *track = trackList[trackIdx];
403
404 if( !track->IsOnLayer( layer ) )
405 continue;
406
407 // ADD VIAS and THT
408 if( track->Type() == PCB_VIA_T )
409 {
410 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
411 const VIATYPE viatype = via->GetViaType();
412
413 if( viatype != VIATYPE::THROUGH )
414 {
415 // Add PCB_VIA hole contours
416
417 // Add outer holes of VIAs
418 SHAPE_POLY_SET *layerOuterHolesPoly = nullptr;
419 SHAPE_POLY_SET *layerInnerHolesPoly = nullptr;
420
421 // Check if the layer is already created
422 if( !m_layerHoleOdPolys.contains( layer ) )
423 {
424 // not found, create a new container
425 layerOuterHolesPoly = new SHAPE_POLY_SET;
426 m_layerHoleOdPolys[layer] = layerOuterHolesPoly;
427
428 wxASSERT( !m_layerHoleIdPolys.contains( layer ) );
429
430 layerInnerHolesPoly = new SHAPE_POLY_SET;
431 m_layerHoleIdPolys[layer] = layerInnerHolesPoly;
432 }
433 else
434 {
435 // found
436 layerOuterHolesPoly = m_layerHoleOdPolys[layer];
437
438 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
439
440 layerInnerHolesPoly = m_layerHoleIdPolys[layer];
441 }
442
443 const int holediameter = via->GetDrillValue();
444 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
445
446 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(), hole_outer_radius,
447 via->GetMaxError(), ERROR_INSIDE );
448
449 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(), holediameter / 2,
450 via->GetMaxError(), ERROR_INSIDE );
451 }
452 else if( layer == layer_ids[0] ) // it only adds once the THT holes
453 {
454 const int holediameter = via->GetDrillValue();
455 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
456 const int hole_outer_ring_radius = KiROUND( via->GetWidth( layer ) / 2.0 );
457
458 // Add through hole contours
459 TransformCircleToPolygon( m_TH_ODPolys, via->GetStart(), hole_outer_radius,
460 via->GetMaxError(), ERROR_INSIDE );
461
462 // Add same thing for vias only
463 TransformCircleToPolygon( m_viaTH_ODPolys, via->GetStart(), hole_outer_radius,
464 via->GetMaxError(), ERROR_INSIDE );
465
467 {
468 TransformCircleToPolygon( m_viaAnnuliPolys, via->GetStart(), hole_outer_ring_radius,
469 via->GetMaxError(), ERROR_INSIDE );
470 }
471 }
472 }
473 }
474 }
475
476 // Creates vertical outline contours of the tracks and add it to the poly of the layer
477 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
478 {
479 for( PCB_LAYER_ID layer : layer_ids )
480 {
481 wxASSERT( m_layers_poly.contains( layer ) );
482
483 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
484
485 // ADD TRACKS
486 unsigned int nTracks = trackList.size();
487
488 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
489 {
490 const PCB_TRACK *track = trackList[trackIdx];
491
492 if( !track->IsOnLayer( layer ) )
493 continue;
494
495 // Skip vias annulus when not flashed on this layer
496 if( track->Type() == PCB_VIA_T && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
497 continue;
498
499 // Add the track/via contour
500 track->TransformShapeToPolygon( *layerPoly, layer, 0, track->GetMaxError(), ERROR_INSIDE );
501 }
502 }
503 }
504
505 // Add holes of footprints
506 for( FOOTPRINT* footprint : m_board->Footprints() )
507 {
508 for( PAD* pad : footprint->Pads() )
509 {
510 const VECTOR2I 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, if not plated, no copper
516 int inflate = 0;
517
518 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
519 inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
520
521 m_holeCount++;
522 double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
523 m_averageHoleDiameter += static_cast<float>( holeDiameter * m_biuTo3Dunits );
524
525 createPadWithHole( pad, &m_TH_ODs, inflate );
526
528 createPadWithHole( pad, &m_viaAnnuli, inflate );
529
531 }
532 }
533
534 if( m_holeCount )
536
537 // Add contours of the pad holes (pads can be Circle or Segment holes)
538 for( FOOTPRINT* footprint : m_board->Footprints() )
539 {
540 for( PAD* pad : footprint->Pads() )
541 {
542 const VECTOR2I padHole = pad->GetDrillSize();
543
544 if( !padHole.x ) // Not drilled pad like SMD pad
545 continue;
546
547 // The hole in the body is inflated by copper thickness.
548 const int inflate = GetHolePlatingThickness();
549
550 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
551 {
553 pad->TransformHoleToPolygon( m_viaAnnuliPolys, inflate, pad->GetMaxError(), ERROR_INSIDE );
554
555 pad->TransformHoleToPolygon( m_TH_ODPolys, inflate, pad->GetMaxError(), ERROR_INSIDE );
556 }
557 else
558 {
559 // If not plated, no copper.
561 pad->TransformHoleToPolygon( m_viaAnnuliPolys, 0, pad->GetMaxError(), ERROR_INSIDE );
562
563 pad->TransformHoleToPolygon( m_NPTH_ODPolys, 0, pad->GetMaxError(), ERROR_INSIDE );
564 }
565 }
566 }
567
568 // Add footprints copper items (pads, shapes and text) to containers
569 for( PCB_LAYER_ID layer : layer_ids )
570 {
571 wxASSERT( m_layerMap.contains( layer ) );
572
573 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
574
575 for( FOOTPRINT* fp : m_board->Footprints() )
576 {
577 addPads( fp, layerContainer, layer );
578 addFootprintShapes( fp, layerContainer, layer, visibilityFlags );
579
580 // Add copper item to the plated copper polygon list if required
582 {
584
585 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), ERROR_INSIDE );
586 transformFPTextToPolySet( fp, layer, visibilityFlags, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
587 transformFPShapesToPolySet( fp, layer, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
588 }
589
590 // Add copper item to poly contours (vertical outlines) if required
591 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
592 {
593 wxASSERT( m_layers_poly.contains( layer ) );
594
595 SHAPE_POLY_SET* layerPoly = m_layers_poly[layer];
596
597 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), ERROR_INSIDE );
598 transformFPTextToPolySet( fp, layer, visibilityFlags, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
599 transformFPShapesToPolySet( fp, layer, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
600 }
601 }
602 }
603
604 // Add graphic item on copper layers to object containers
605 for( PCB_LAYER_ID layer : layer_ids )
606 {
607 wxASSERT( m_layerMap.contains( layer ) );
608
609 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
610
611 // Add graphic items on copper layers (texts and other graphics)
612 for( BOARD_ITEM* item : m_board->Drawings() )
613 {
614 if( !item->IsOnLayer( layer ) )
615 continue;
616
617 switch( item->Type() )
618 {
619 case PCB_SHAPE_T:
620 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
621 break;
622
623 case PCB_TEXT_T:
624 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
625 break;
626
627 case PCB_TEXTBOX_T:
628 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
629 break;
630
631 case PCB_TABLE_T:
632 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
633 break;
634
636 case PCB_DIM_CENTER_T:
637 case PCB_DIM_RADIAL_T:
639 case PCB_DIM_LEADER_T:
640 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
641 break;
642
643 case PCB_REFERENCE_IMAGE_T: // ignore
644 break;
645
646 default:
647 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), item->Type() );
648 break;
649 }
650
651 // Add copper item to the plated copper polygon list if required
653 {
655
656 // Note: for TEXT and TEXTBOX, TransformShapeToPolygon returns the bounding
657 // box shape, not the exact text shape. So it is not used for these items
658 if( item->Type() == PCB_TEXTBOX_T )
659 {
660 PCB_TEXTBOX* text_box = static_cast<PCB_TEXTBOX*>( item );
661 text_box->TransformTextToPolySet( *copperPolys, 0, text_box->GetMaxError(), ERROR_INSIDE );
662
663 // Add box outlines
664 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, text_box->GetMaxError(),
665 ERROR_INSIDE );
666 }
667 else if( item->Type() == PCB_TEXT_T )
668 {
669 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
670 text->TransformTextToPolySet( *copperPolys, 0, text->GetMaxError(), ERROR_INSIDE );
671 }
672 else if( item->Type() != PCB_REFERENCE_IMAGE_T )
673 {
674 item->TransformShapeToPolySet( *copperPolys, layer, 0, item->GetMaxError(), ERROR_INSIDE );
675 }
676 }
677
678 // Add copper item to poly contours (vertical outlines) if required
679 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
680 {
681 wxASSERT( m_layers_poly.contains( layer ) );
682
683 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
684
685 switch( item->Type() )
686 {
687 case PCB_SHAPE_T:
688 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), ERROR_INSIDE );
689 break;
690
691 case PCB_TEXT_T:
692 {
693 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
694
695 text->TransformTextToPolySet( *layerPoly, 0, text->GetMaxError(), ERROR_INSIDE );
696 break;
697 }
698
699 case PCB_TEXTBOX_T:
700 {
701 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
702
703 if( textbox->IsBorderEnabled() )
704 {
705 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->GetMaxError(),
706 ERROR_INSIDE );
707 }
708
709 textbox->TransformTextToPolySet( *layerPoly, 0, textbox->GetMaxError(), ERROR_INSIDE );
710 break;
711 }
712
713 case PCB_TABLE_T:
714 {
715 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
716
717 for( PCB_TABLECELL* cell : table->GetCells() )
718 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), ERROR_INSIDE );
719
720 table->DrawBorders(
721 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
722 const STROKE_PARAMS& stroke )
723 {
724 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
725 seg.TransformToPolygon( *layerPoly, table->GetMaxError(), ERROR_INSIDE );
726 } );
727 break;
728 }
729
731 case PCB_DIM_CENTER_T:
732 case PCB_DIM_RADIAL_T:
734 case PCB_DIM_LEADER_T:
735 {
736 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
737
738 dimension->TransformTextToPolySet( *layerPoly, 0, dimension->GetMaxError(), ERROR_INSIDE );
739
740 for( const std::shared_ptr<SHAPE>& shape : dimension->GetShapes() )
741 shape->TransformToPolygon( *layerPoly, dimension->GetMaxError(), ERROR_INSIDE );
742
743 break;
744 }
745
746 case PCB_REFERENCE_IMAGE_T: // ignore
747 break;
748
749 default:
750 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), item->Type() );
751 break;
752 }
753 }
754 }
755 }
756
757 if( cfg.show_zones )
758 {
759 if( aStatusReporter )
760 aStatusReporter->Report( _( "Create zones" ) );
761
762 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
763 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
764
765 for( ZONE* zone : m_board->Zones() )
766 {
767 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
768 {
769 zones.emplace_back( std::make_pair( zone, layer ) );
770 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
771
773 {
775
776 zone->TransformShapeToPolygon( *copperPolys, layer, 0, zone->GetMaxError(), ERROR_INSIDE );
777 }
778 }
779 }
780
781 // Add zones objects
782 std::atomic<size_t> nextZone( 0 );
783 std::atomic<size_t> threadsFinished( 0 );
784
785 size_t parallelThreadCount = std::min<size_t>( zones.size(),
786 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
787
788 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
789 {
790 std::thread t = std::thread( [&]()
791 {
792 for( size_t areaId = nextZone.fetch_add( 1 );
793 areaId < zones.size();
794 areaId = nextZone.fetch_add( 1 ) )
795 {
796 ZONE* zone = zones[areaId].first;
797
798 if( zone == nullptr )
799 break;
800
801 PCB_LAYER_ID layer = zones[areaId].second;
802
803 if( m_layerMap.contains( layer ) )
804 addSolidAreasShapes( zone, m_layerMap[layer], layer );
805
806 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
807 && m_layers_poly.contains( layer ) )
808 {
809 auto mut_it = layer_lock.find( layer );
810
811 if( mut_it != layer_lock.end() )
812 {
813 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
814 zone->TransformSolidAreasShapesToPolygon( layer, *m_layers_poly[layer] );
815 }
816 }
817 }
818
819 threadsFinished++;
820 } );
821
822 t.detach();
823 }
824
825 while( threadsFinished < parallelThreadCount )
826 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
827 }
828 // End Build Copper layers
829
830 // This will make a union of all added contours
831 m_TH_ODPolys.Simplify();
832 m_NPTH_ODPolys.Simplify();
833 m_viaTH_ODPolys.Simplify();
834 m_viaAnnuliPolys.Simplify();
835
836 // Build Tech layers
837 // Based on:
838 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
839 if( aStatusReporter )
840 aStatusReporter->Report( _( "Build Tech layers" ) );
841
842 // draw graphic items, on technical layers
843
844 LSEQ techLayerList = LSET::AllNonCuMask().Seq( {
845 B_Adhes,
846 F_Adhes,
847 B_Paste,
848 F_Paste,
849 B_SilkS,
850 F_SilkS,
851 B_Mask,
852 F_Mask,
853
854 // Aux Layers
855 Dwgs_User,
856 Cmts_User,
857 Eco1_User,
858 Eco2_User,
859 User_1,
860 User_2,
861 User_3,
862 User_4,
863 User_5,
864 User_6,
865 User_7,
866 User_8,
867 User_9,
868 User_10,
869 User_11,
870 User_12,
871 User_13,
872 User_14,
873 User_15,
874 User_16,
875 User_17,
876 User_18,
877 User_19,
878 User_20,
879 User_21,
880 User_22,
881 User_23,
882 User_24,
883 User_25,
884 User_26,
885 User_27,
886 User_28,
887 User_29,
888 User_30,
889 User_31,
890 User_32,
891 User_33,
892 User_34,
893 User_35,
894 User_36,
895 User_37,
896 User_38,
897 User_39,
898 User_40,
899 User_41,
900 User_42,
901 User_43,
902 User_44,
903 User_45,
904 } );
905
906 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
907
908 if( cfg.subtract_mask_from_silk || cfg.DifferentiatePlatedCopper() )
909 {
910 enabledFlags.set( LAYER_3D_SOLDERMASK_TOP );
911 enabledFlags.set( LAYER_3D_SOLDERMASK_BOTTOM );
912 }
913
914 for( PCB_LAYER_ID layer : techLayerList )
915 {
916 if( aStatusReporter )
917 aStatusReporter->Report( wxString::Format( _( "Build Tech layer %d" ), (int) layer ) );
918
919 if( !Is3dLayerEnabled( layer, enabledFlags ) )
920 continue;
921
922 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
923 m_layerMap[layer] = layerContainer;
924
925 SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
926 m_layers_poly[layer] = layerPoly;
927
928 if( Is3dLayerEnabled( layer, visibilityFlags ) )
929 {
930 // Add drawing objects
931 for( BOARD_ITEM* item : m_board->Drawings() )
932 {
933 if( !item->IsOnLayer( layer ) )
934 continue;
935
936 switch( item->Type() )
937 {
938 case PCB_SHAPE_T:
939 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
940 break;
941
942 case PCB_TEXT_T:
943 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
944 break;
945
946 case PCB_TEXTBOX_T:
947 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
948 break;
949
950 case PCB_TABLE_T:
951 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
952 break;
953
955 case PCB_DIM_CENTER_T:
956 case PCB_DIM_RADIAL_T:
958 case PCB_DIM_LEADER_T:
959 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
960 break;
961
962 default:
963 break;
964 }
965 }
966
967 // Add track, via and arc tech layers
968 if( IsSolderMaskLayer( layer ) )
969 {
970 for( PCB_TRACK* track : m_board->Tracks() )
971 {
972 if( !track->IsOnLayer( layer ) )
973 continue;
974
975 // Only vias on a external copper layer can have a solder mask
976 PCB_LAYER_ID copper_layer = ( layer == F_Mask ) ? F_Cu : B_Cu;
977
978 if( track->Type() == PCB_VIA_T )
979 {
980 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
981
982 if( !via->FlashLayer( copper_layer ) )
983 continue;
984 }
985
986 int maskExpansion = track->GetSolderMaskExpansion();
987 createTrackWithMargin( track, layerContainer, layer, maskExpansion );
988 }
989 }
990
991 // Add footprints tech layers - objects
992 for( FOOTPRINT* footprint : m_board->Footprints() )
993 {
994 if( layer == F_SilkS || layer == B_SilkS )
995 {
996 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
997
998 for( PAD* pad : footprint->Pads() )
999 {
1000 if( !pad->IsOnLayer( layer ) )
1001 continue;
1002
1003 buildPadOutlineAsSegments( pad, layer, layerContainer, linewidth );
1004 }
1005 }
1006 else
1007 {
1008 addPads( footprint, layerContainer, layer );
1009 }
1010
1011 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
1012 }
1013
1014 // Draw non copper zones
1015 if( cfg.show_zones )
1016 {
1017 for( ZONE* zone : m_board->Zones() )
1018 {
1019 if( zone->IsOnLayer( layer ) )
1020 addSolidAreasShapes( zone, layerContainer, layer );
1021 }
1022 }
1023 }
1024
1025 // Add item contours. We need these if we're building vertical walls or if this is a
1026 // mask layer and we're differentiating copper from plated copper.
1027 if( ( cfg.engine == RENDER_ENGINE::OPENGL && cfg.opengl_copper_thickness )
1028 || ( cfg.DifferentiatePlatedCopper() && ( layer == F_Mask || layer == B_Mask ) ) )
1029 {
1030 // DRAWINGS
1031 for( BOARD_ITEM* item : m_board->Drawings() )
1032 {
1033 if( !item->IsOnLayer( layer ) )
1034 continue;
1035
1036 switch( item->Type() )
1037 {
1038 case PCB_SHAPE_T:
1039 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), ERROR_INSIDE );
1040 break;
1041
1042 case PCB_TEXT_T:
1043 {
1044 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1045
1046 text->TransformTextToPolySet( *layerPoly, 0, text->GetMaxError(), ERROR_INSIDE );
1047 break;
1048 }
1049
1050 case PCB_TEXTBOX_T:
1051 {
1052 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
1053
1054 if( textbox->IsBorderEnabled() )
1055 {
1056 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->GetMaxError(),
1057 ERROR_INSIDE );
1058 }
1059
1060 textbox->TransformTextToPolySet( *layerPoly, 0, textbox->GetMaxError(), ERROR_INSIDE );
1061 break;
1062 }
1063
1064 case PCB_TABLE_T:
1065 {
1066 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
1067
1068 for( PCB_TABLECELL* cell : table->GetCells() )
1069 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), ERROR_INSIDE );
1070
1071 table->DrawBorders(
1072 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
1073 const STROKE_PARAMS& stroke )
1074 {
1075 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
1076 seg.TransformToPolygon( *layerPoly, table->GetMaxError(), ERROR_INSIDE );
1077 } );
1078
1079 break;
1080 }
1081
1082 default:
1083 break;
1084 }
1085 }
1086
1087 // NON-TENTED VIAS
1088 if( ( layer == F_Mask || layer == B_Mask ) )
1089 {
1090 int maskExpansion = GetBoard()->GetDesignSettings().m_SolderMaskExpansion;
1091
1092 for( PCB_TRACK* track : m_board->Tracks() )
1093 {
1094 if( track->Type() == PCB_VIA_T )
1095 {
1096 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1097
1098 if( via->FlashLayer( layer ) && !via->IsTented( layer ) )
1099 {
1100 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1101 ERROR_INSIDE );
1102 }
1103 }
1104 else
1105 {
1106 if( track->HasSolderMask() )
1107 {
1108 track->TransformShapeToPolySet( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1109 ERROR_INSIDE );
1110 }
1111 }
1112 }
1113 }
1114
1115 // FOOTPRINT CHILDREN
1116 for( FOOTPRINT* footprint : m_board->Footprints() )
1117 {
1118 if( layer == F_SilkS || layer == B_SilkS )
1119 {
1120 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
1121
1122 for( PAD* pad : footprint->Pads() )
1123 {
1124 if( pad->IsOnLayer( layer ) )
1125 {
1126 buildPadOutlineAsPolygon( pad, layer, *layerPoly, linewidth, pad->GetMaxError(),
1127 ERROR_INSIDE );
1128 }
1129 }
1130 }
1131 else
1132 {
1133 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, footprint->GetMaxError(), ERROR_INSIDE );
1134 }
1135
1136 transformFPTextToPolySet( footprint, layer, visibilityFlags, *layerPoly, footprint->GetMaxError(),
1137 ERROR_INSIDE );
1138 transformFPShapesToPolySet( footprint, layer, *layerPoly, footprint->GetMaxError(), ERROR_INSIDE );
1139 }
1140
1141 if( cfg.show_zones || layer == F_Mask || layer == B_Mask )
1142 {
1143 for( ZONE* zone : m_board->Zones() )
1144 {
1145 if( zone->IsOnLayer( layer ) )
1146 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1147 }
1148 }
1149
1150 // This will make a union of all added contours
1151 layerPoly->Simplify();
1152 }
1153 }
1154 // End Build Tech layers
1155
1156 // If we're rendering off-board silk, also render pads of footprints which are entirely
1157 // outside the board outline. This makes off-board footprints more visually recognizable.
1158 if( cfg.show_off_board_silk )
1159 {
1160 BOX2I boardBBox = m_board_poly.BBox();
1161
1162 for( FOOTPRINT* footprint : m_board->Footprints() )
1163 {
1164 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1165 {
1166 if( footprint->IsFlipped() )
1167 addPads( footprint, m_offboardPadsBack, B_Cu );
1168 else
1169 addPads( footprint, m_offboardPadsFront, F_Cu );
1170 }
1171 }
1172
1173 m_offboardPadsFront->BuildBVH();
1174 m_offboardPadsBack->BuildBVH();
1175 }
1176
1177 // Simplify layer polygons
1178
1179 if( aStatusReporter )
1180 aStatusReporter->Report( _( "Simplifying copper layer polygons" ) );
1181
1182 if( cfg.DifferentiatePlatedCopper() )
1183 {
1184 if( aStatusReporter )
1185 aStatusReporter->Report( _( "Calculating plated copper" ) );
1186
1187 // TRIM PLATED COPPER TO SOLDERMASK
1188 if( m_layers_poly.contains( F_Mask ) )
1189 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( F_Mask ) );
1190
1191 if( m_layers_poly.contains( B_Mask ))
1192 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( B_Mask ) );
1193
1194 // Subtract plated copper from unplated copper
1195 if( m_layers_poly.contains( F_Cu ) )
1196 m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys );
1197
1198 if( m_layers_poly.contains( B_Cu ) )
1199 m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys );
1200
1201 // ADD PLATED COPPER
1202 ConvertPolygonToTriangles( *m_frontPlatedCopperPolys, *m_platedPadsFront, m_biuTo3Dunits,
1204
1205 ConvertPolygonToTriangles( *m_backPlatedCopperPolys, *m_platedPadsBack, m_biuTo3Dunits,
1207
1208 m_platedPadsFront->BuildBVH();
1209 m_platedPadsBack->BuildBVH();
1210 }
1211
1212 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
1213 {
1214 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1215 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1216
1217 if( cfg.DifferentiatePlatedCopper() )
1218 {
1219 layer_id_without_F_and_B.clear();
1220 layer_id_without_F_and_B.reserve( layer_ids.size() );
1221
1222 for( PCB_LAYER_ID layer: layer_ids )
1223 {
1224 if( layer != F_Cu && layer != B_Cu )
1225 layer_id_without_F_and_B.push_back( layer );
1226 }
1227
1228 selected_layer_id = layer_id_without_F_and_B;
1229 }
1230
1231 if( selected_layer_id.size() > 0 )
1232 {
1233 if( aStatusReporter )
1234 {
1235 aStatusReporter->Report( wxString::Format( _( "Simplifying %d copper layers" ),
1236 (int) selected_layer_id.size() ) );
1237 }
1238
1239 std::atomic<size_t> nextItem( 0 );
1240 std::atomic<size_t> threadsFinished( 0 );
1241
1242 size_t parallelThreadCount = std::min<size_t>(
1243 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1244 selected_layer_id.size() );
1245
1246 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1247 {
1248 std::thread t = std::thread(
1249 [&nextItem, &threadsFinished, &selected_layer_id, this]()
1250 {
1251 for( size_t i = nextItem.fetch_add( 1 );
1252 i < selected_layer_id.size();
1253 i = nextItem.fetch_add( 1 ) )
1254 {
1255 if( m_layers_poly.contains( selected_layer_id[i] ) )
1256 {
1257 // This will make a union of all added contours
1258 m_layers_poly[ selected_layer_id[i] ]->ClearArcs();
1259 m_layers_poly[ selected_layer_id[i] ]->Simplify();
1260 }
1261 }
1262
1263 threadsFinished++;
1264 } );
1265
1266 t.detach();
1267 }
1268
1269 while( threadsFinished < parallelThreadCount )
1270 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1271 }
1272 }
1273
1274 // Simplify holes polygon contours
1275 if( aStatusReporter )
1276 aStatusReporter->Report( _( "Simplify holes contours" ) );
1277
1278 for( PCB_LAYER_ID layer : layer_ids )
1279 {
1280 if( m_layerHoleOdPolys.contains( layer ) )
1281 {
1282 // found
1283 SHAPE_POLY_SET *polyLayer = m_layerHoleOdPolys[layer];
1284 polyLayer->Simplify();
1285
1286 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
1287
1288 polyLayer = m_layerHoleIdPolys[layer];
1289 polyLayer->Simplify();
1290 }
1291 }
1292
1293 // Build BVH (Bounding volume hierarchy) for holes and vias
1294
1295 if( aStatusReporter )
1296 aStatusReporter->Report( _( "Build BVH for holes and vias" ) );
1297
1298 m_TH_IDs.BuildBVH();
1299 m_TH_ODs.BuildBVH();
1300 m_viaAnnuli.BuildBVH();
1301
1302 if( !m_layerHoleMap.empty() )
1303 {
1304 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1305 hole.second->BuildBVH();
1306 }
1307
1308 // We only need the Solder mask to initialize the BVH
1309 // because..?
1310 if( m_layerMap[B_Mask] )
1311 m_layerMap[B_Mask]->BuildBVH();
1312
1313 if( m_layerMap[F_Mask] )
1314 m_layerMap[F_Mask]->BuildBVH();
1315}
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Definition: approximation.h:32
@ ERROR_INSIDE
Definition: approximation.h:34
@ LAYER_CLASS_SILK
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
MAP_CONTAINER_2D_BASE m_layerHoleMap
Holes for each layer.
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
BVH_CONTAINER_2D * m_offboardPadsBack
void createLayers(REPORTER *aStatusReporter)
SHAPE_POLY_SET m_TH_ODPolys
PTH outer diameters.
void addPads(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
unsigned int m_viaCount
void createTrackWithMargin(const PCB_TRACK *aTrack, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayer, int aMargin=0)
MAP_POLY m_layerHoleOdPolys
Hole outer diameters (per layer)
SHAPE_POLY_SET * m_frontPlatedCopperPolys
MAP_CONTAINER_2D_BASE m_layerMap
2D elements for each layer.
BVH_CONTAINER_2D m_TH_ODs
List of PTH outer diameters.
unsigned int m_trackCount
float m_averageTrackWidth
std::bitset< LAYER_3D_END > GetVisibleLayers() const
void addFootprintShapes(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId, const std::bitset< LAYER_3D_END > &aVisibilityFlags)
MAP_POLY m_layerHoleIdPolys
Hole inner diameters (per layer)
int GetHolePlatingThickness() const noexcept
Get the hole plating thickness (NB: in BOARD UNITS!).
SHAPE_POLY_SET m_viaAnnuliPolys
Via annular ring outer diameters.
BVH_CONTAINER_2D * m_offboardPadsFront
float m_averageViaHoleDiameter
BVH_CONTAINER_2D m_viaTH_ODs
List of via hole outer diameters.
float m_averageHoleDiameter
SHAPE_POLY_SET m_viaTH_ODPolys
Via hole outer diameters.
BVH_CONTAINER_2D * m_platedPadsBack
void createPadWithHole(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aInflateValue)
MAP_POLY m_layers_poly
Amalgamated polygon contours for various types of items.
SHAPE_POLY_SET * m_backPlatedCopperPolys
EDA_3D_VIEWER_SETTINGS * m_Cfg
void addTable(const PCB_TABLE *aTable, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner)
unsigned int m_holeCount
BVH_CONTAINER_2D m_viaAnnuli
List of via annular rings.
unsigned int m_copperLayersCount
BVH_CONTAINER_2D m_TH_IDs
List of PTH inner diameters.
BVH_CONTAINER_2D * m_platedPadsFront
void addShape(const PCB_SHAPE *aShape, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner, PCB_LAYER_ID aLayer)
SHAPE_POLY_SET m_NPTH_ODPolys
NPTH outer diameters.
bool Is3dLayerEnabled(PCB_LAYER_ID aLayer, const std::bitset< LAYER_3D_END > &aVisibilityFlags) const
Check if a layer is enabled.
double m_biuTo3Dunits
Scale factor to convert board internal units to 3D units normalized between -1.0 and 1....
void addText(const EDA_TEXT *aText, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM *aOwner)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
int GetMaxError() const
Definition: board_item.cpp:138
const ZONES & Zones() const
Definition: board.h:362
const FOOTPRINTS & Footprints() const
Definition: board.h:358
const TRACKS & Tracks() const
Definition: board.h:356
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1023
const DRAWINGS & Drawings() const
Definition: board.h:360
void Clear() override
void Add(OBJECT_2D *aObject)
Definition: container_2d.h:49
static DELETED_BOARD_ITEM * GetInstance()
Definition: board_item.h:491
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:109
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:634
DRAWINGS & GraphicalItems()
Definition: footprint.h:212
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: lseq.h:47
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:610
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:296
Definition: pad.h:54
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:195
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:514
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1049
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:264
Abstract dimension API.
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:71
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
Definition: pcb_text.cpp:553
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the track shape to a closed polygon.
Definition: pcb_track.cpp:2260
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pcb_track.cpp:1156
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
Definition: pcb_track.cpp:1426
int GetSolderMaskExpansion() const
Definition: pcb_track.cpp:1120
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition: reporter.h:102
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
Simple container to manage line stroke parameters.
Definition: stroke_params.h:94
int GetWidth() const
Handle a list of polygons defining a copper zone.
Definition: zone.h:74
void TransformRingToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aCentre, int aRadius, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arcs to multiple straight segments.
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define DELETE_AND_FREE_MAP(map)
void transformFPShapesToPolySet(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer, int aMaxError, ERROR_LOC aErrorLoc)
void transformFPTextToPolySet(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, const std::bitset< LAYER_3D_END > &aFlags, SHAPE_POLY_SET &aBuffer, int aMaxError, ERROR_LOC aErrorLoc)
void buildPadOutlineAsPolygon(const PAD *aPad, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer, int aWidth, int aMaxError, ERROR_LOC aErrorLoc)
#define DELETE_AND_FREE(ptr)
#define _(s)
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
bool IsSolderMaskLayer(int aLayer)
Definition: layer_ids.h:734
@ LAYER_3D_SOLDERMASK_TOP
Definition: layer_ids.h:548
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:547
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition: layer_ids.h:265
@ LAYER_FP_TEXT
Definition: layer_ids.h:239
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition: layer_ids.h:262
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition: layer_ids.h:675
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ User_16
Definition: layer_ids.h:139
@ User_29
Definition: layer_ids.h:152
@ User_40
Definition: layer_ids.h:163
@ User_15
Definition: layer_ids.h:138
@ User_8
Definition: layer_ids.h:131
@ User_11
Definition: layer_ids.h:134
@ User_25
Definition: layer_ids.h:148
@ User_34
Definition: layer_ids.h:157
@ User_45
Definition: layer_ids.h:168
@ B_Adhes
Definition: layer_ids.h:103
@ User_36
Definition: layer_ids.h:159
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ Cmts_User
Definition: layer_ids.h:108
@ User_6
Definition: layer_ids.h:129
@ User_7
Definition: layer_ids.h:130
@ User_19
Definition: layer_ids.h:142
@ User_23
Definition: layer_ids.h:146
@ F_Adhes
Definition: layer_ids.h:102
@ User_41
Definition: layer_ids.h:164
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ User_14
Definition: layer_ids.h:137
@ User_39
Definition: layer_ids.h:162
@ User_5
Definition: layer_ids.h:128
@ User_20
Definition: layer_ids.h:143
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ User_42
Definition: layer_ids.h:165
@ User_43
Definition: layer_ids.h:166
@ B_Paste
Definition: layer_ids.h:105
@ User_10
Definition: layer_ids.h:133
@ User_9
Definition: layer_ids.h:132
@ User_27
Definition: layer_ids.h:150
@ User_28
Definition: layer_ids.h:151
@ F_SilkS
Definition: layer_ids.h:100
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:110
@ User_35
Definition: layer_ids.h:158
@ User_31
Definition: layer_ids.h:154
@ User_3
Definition: layer_ids.h:126
@ User_1
Definition: layer_ids.h:124
@ User_12
Definition: layer_ids.h:135
@ B_SilkS
Definition: layer_ids.h:101
@ User_30
Definition: layer_ids.h:153
@ User_37
Definition: layer_ids.h:160
@ User_22
Definition: layer_ids.h:145
@ User_38
Definition: layer_ids.h:161
@ User_4
Definition: layer_ids.h:127
@ User_21
Definition: layer_ids.h:144
@ User_24
Definition: layer_ids.h:147
@ User_13
Definition: layer_ids.h:136
@ User_2
Definition: layer_ids.h:125
@ User_17
Definition: layer_ids.h:140
@ User_33
Definition: layer_ids.h:156
@ User_26
Definition: layer_ids.h:149
@ User_32
Definition: layer_ids.h:155
@ User_18
Definition: layer_ids.h:141
@ User_44
Definition: layer_ids.h:167
@ F_Cu
Definition: layer_ids.h:64
VIATYPE
Definition: pcb_track.h:66
BOARD * GetBoard()
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
bool DifferentiatePlatedCopper()
return true if platted copper aeras and non platted copper areas must be drawn using a different colo...
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
constexpr KICAD_T BaseType(const KICAD_T aType)
Return the underlying type of the given type.
Definition: typeinfo.h:251
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:100
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition: typeinfo.h:94
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42