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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <vector>
23#include <thread>
24#include <algorithm>
25#include <atomic>
26
27#include <wx/log.h>
28
29#include "board_adapter.h"
33#include <board.h>
34#include <footprint.h>
35#include <layer_range.h>
36#include <lset.h>
38#include <trigo.h>
39#include <pad.h>
40#include <pcb_barcode.h>
41#include <pcb_shape.h>
42#include <pcb_track.h>
43#include <zone.h>
44
45#ifdef PRINT_STATISTICS_3D_VIEWER
46#include <core/profile.h>
47#endif
48
49/*
50 * This is used to draw pad outlines on silk layers.
51 */
52void buildPadOutlineAsPolygon( const PAD* aPad, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aBuffer,
53 int aWidth, int aMaxError, ERROR_LOC aErrorLoc )
54{
55 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
56 {
57 TransformRingToPolygon( aBuffer, aPad->ShapePos( aLayer ), aPad->GetSize( aLayer ).x / 2,
58 aWidth, aMaxError, aErrorLoc );
59 }
60 else
61 {
62 // For other shapes, add outlines as thick segments in polygon buffer
63 const SHAPE_LINE_CHAIN& path = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE )->COutline( 0 );
64
65 for( int ii = 0; ii < path.PointCount(); ++ii )
66 {
67 const VECTOR2I& a = path.CPoint( ii );
68 const VECTOR2I& b = path.CPoint( ii + 1 );
69
70 TransformOvalToPolygon( aBuffer, a, b, aWidth, aMaxError, aErrorLoc );
71 }
72 }
73}
74
75
76void transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
77 SHAPE_POLY_SET& aBuffer, int aMaxError, ERROR_LOC aErrorLoc )
78{
79 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
80 {
81 if( !item->IsOnLayer( aLayer ) )
82 continue;
83
84 switch( item->Type() )
85 {
86 case PCB_SHAPE_T:
87 {
88 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
89 int margin = 0;
90
91 if( IsSolderMaskLayer( aLayer ) && shape->HasSolderMask() )
92 margin = shape->GetSolderMaskExpansion();
93
94 item->TransformShapeToPolySet( aBuffer, aLayer, margin, aMaxError, aErrorLoc );
95 break;
96 }
97
98 case PCB_BARCODE_T:
99 item->TransformShapeToPolySet( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
100 break;
101
103 case PCB_DIM_CENTER_T:
104 case PCB_DIM_RADIAL_T:
106 case PCB_DIM_LEADER_T:
107 item->TransformShapeToPolySet( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
108 break;
109
110 default:
111 break;
112 }
113 }
114}
115
116
117void transformFPTextToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
118 const std::bitset<LAYER_3D_END>& aFlags, SHAPE_POLY_SET& aBuffer,
119 int aMaxError, ERROR_LOC aErrorLoc )
120{
121 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
122 {
123 if( item->Type() == PCB_TEXT_T )
124 {
125 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
126
127 if( !aFlags.test( LAYER_FP_TEXT ) )
128 continue;
129
130 if( text->GetText() == wxT( "${REFERENCE}" ) && !aFlags.test( LAYER_FP_REFERENCES ) )
131 continue;
132
133 if( text->GetText() == wxT( "${VALUE}" ) && !aFlags.test( LAYER_FP_VALUES ) )
134 continue;
135
136 if( text->IsOnLayer( aLayer ) )
137 text->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
138 }
139
140 if( item->Type() == PCB_TEXTBOX_T )
141 {
142 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
143
144 if( textbox->IsOnLayer( aLayer ) )
145 {
146 // border
147 if( textbox->IsBorderEnabled() )
148 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
149
150 // text
151 textbox->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
152 }
153 }
154 }
155
156 for( const PCB_FIELD* field : aFootprint->GetFields() )
157 {
158 if( !aFlags.test( LAYER_FP_TEXT ) )
159 continue;
160
161 wxCHECK2( field, continue );
162
163 if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) )
164 continue;
165
166 if( field->IsValue() && !aFlags.test( LAYER_FP_VALUES ) )
167 continue;
168
169 if( field->IsOnLayer( aLayer ) && field->IsVisible() )
170 field->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
171 }
172}
173
174
176{
177#define DELETE_AND_FREE( ptr ) \
178 { \
179 delete ptr; \
180 ptr = nullptr; \
181 } \
182
183#define DELETE_AND_FREE_MAP( map ) \
184 { \
185 for( auto& [ layer, poly ] : map ) \
186 delete poly; \
187 \
188 map.clear(); \
189 }
190
192
195
198
199 m_NPTH_ODPolys.RemoveAllContours();
200 m_TH_ODPolys.RemoveAllContours();
201 m_viaTH_ODPolys.RemoveAllContours();
202 m_viaAnnuliPolys.RemoveAllContours();
203
204 m_frontCounterborePolys.RemoveAllContours();
205 m_backCounterborePolys.RemoveAllContours();
206 m_frontCountersinkPolys.RemoveAllContours();
207 m_backCountersinkPolys.RemoveAllContours();
208
211
216
217 m_TH_ODs.Clear();
218 m_TH_IDs.Clear();
219 m_viaAnnuli.Clear();
220 m_viaTH_ODs.Clear();
221
226 m_backdrillCutouts.Clear();
228}
229
230
231void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
232{
234
235 // Build Copper layers
236 // Based on:
237 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
238
239#ifdef PRINT_STATISTICS_3D_VIEWER
240 int64_t stats_startCopperLayersTime = GetRunningMicroSecs();
241
242 int64_t start_Time = stats_startCopperLayersTime;
243#endif
244
246
247 std::bitset<LAYER_3D_END> visibilityFlags = GetVisibleLayers();
248
249 m_trackCount = 0;
251 m_viaCount = 0;
253 m_holeCount = 0;
255
256 if( !m_board )
257 return;
258
259 // Prepare track list, convert in a vector. Calc statistic for the holes
260 std::vector<const PCB_TRACK*> trackList;
261 trackList.clear();
262 trackList.reserve( m_board->Tracks().size() );
263
264 for( PCB_TRACK* track : m_board->Tracks() )
265 {
266 // Skip tracks (not vias theyt are on more than one layer ) on disabled layers
267 if( track->Type() != PCB_VIA_T && !Is3dLayerEnabled( track->GetLayer(), visibilityFlags ) )
268 {
269 continue;
270 }
271
272 // Note: a PCB_TRACK holds normal segment tracks and also vias circles (that have also
273 // drill values)
274 trackList.push_back( track );
275
276 if( track->Type() == PCB_VIA_T )
277 {
278 const PCB_VIA *via = static_cast< const PCB_VIA*>( track );
279 m_viaCount++;
280 m_averageViaHoleDiameter += static_cast<float>( via->GetDrillValue() * m_biuTo3Dunits );
281 }
282 else
283 {
284 m_trackCount++;
285 m_averageTrackWidth += static_cast<float>( track->GetWidth() * m_biuTo3Dunits );
286 }
287 }
288
289 if( m_trackCount )
291
292 if( m_viaCount )
294
295 // Prepare copper layers index and containers
296 std::vector<PCB_LAYER_ID> layer_ids;
297 layer_ids.clear();
298 layer_ids.reserve( m_copperLayersCount );
299
301 {
302 if( !Is3dLayerEnabled( layer, visibilityFlags ) ) // Skip non enabled layers
303 continue;
304
305 layer_ids.push_back( layer );
306
307 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
308 m_layerMap[layer] = layerContainer;
309
311 {
312 SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
313 m_layers_poly[layer] = layerPoly;
314 }
315 }
316
317 if( cfg.DifferentiatePlatedCopper() )
318 {
321
324 }
325
326 if( cfg.show_off_board_silk )
327 {
330 }
331
332 if( aStatusReporter )
333 aStatusReporter->Report( _( "Create tracks and vias" ) );
334
335 // Create tracks as objects and add it to container
336 for( PCB_LAYER_ID layer : layer_ids )
337 {
338 wxASSERT( m_layerMap.contains( layer ) );
339
340 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
341
342 for( const PCB_TRACK* track : trackList )
343 {
344 // NOTE: Vias can be on multiple layers
345 if( !track->IsOnLayer( layer ) )
346 continue;
347
348 // Skip vias annulus when not flashed on this layer
349 if( track->Type() == PCB_VIA_T && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
350 continue;
351
352 // Add object item to layer container
353 createTrackWithMargin( track, layerContainer, layer );
354 }
355 }
356
357 // Create VIAS and THTs objects and add it to holes containers
358 for( PCB_LAYER_ID layer : layer_ids )
359 {
360 // Check if the layer is already created
361 if( !m_layerHoleMap.contains( layer ) )
362 {
363 m_layerHoleMap[layer] = new BVH_CONTAINER_2D;
364 }
365
366 // ADD TRACKS
367 unsigned int nTracks = trackList.size();
368
369 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
370 {
371 const PCB_TRACK *track = trackList[trackIdx];
372
373 if( !track->IsOnLayer( layer ) )
374 continue;
375
376 // ADD VIAS and THT
377 if( track->Type() == PCB_VIA_T )
378 {
379 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
380 const VIATYPE viatype = via->GetViaType();
381 const double holediameter = via->GetDrillValue() * BiuTo3dUnits();
382 const double viasize = via->GetWidth( layer ) * BiuTo3dUnits();
383 const double plating = GetHolePlatingThickness() * BiuTo3dUnits();
384
385 // holes and layer copper extend half info cylinder wall to hide transition
386 const float thickness = static_cast<float>( plating / 2.0f );
387 const float hole_inner_radius = static_cast<float>( holediameter / 2.0f );
388 const float ring_radius = static_cast<float>( viasize / 2.0f );
389
390 const SFVEC2F via_center( via->GetStart().x * m_biuTo3Dunits,
391 -via->GetStart().y * m_biuTo3Dunits );
392
393 if( viatype != VIATYPE::THROUGH )
394 {
395 // Add hole objects
396 BVH_CONTAINER_2D *layerHoleContainer = nullptr;
397 layerHoleContainer = m_layerHoleMap[layer];
398
399 // Add a hole for this layer
400 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness,
401 *track ) );
402 }
403 else if( layer == layer_ids[0] ) // it only adds once the THT holes
404 {
405 // Add through hole object
406 m_TH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
407 m_viaTH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
408
409 if( cfg.clip_silk_on_via_annuli && ring_radius > 0.0 )
410 m_viaAnnuli.Add( new FILLED_CIRCLE_2D( via_center, ring_radius, *track ) );
411
412 if( hole_inner_radius > 0.0 )
413 m_TH_IDs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius, *track ) );
414 }
415
416 // Add counterbore/countersink cutouts for vias
417 const auto frontMode = via->GetFrontPostMachining().value_or( PAD_DRILL_POST_MACHINING_MODE::UNKNOWN );
418 const double frontRadius = via->GetFrontPostMachiningSize() * m_biuTo3Dunits / 2.0;
419
422 && frontRadius > hole_inner_radius )
423 {
424 if( layer == layer_ids[0] ) // only add once for front layer
425 {
427 m_frontCounterboreCutouts.Add( new FILLED_CIRCLE_2D( via_center, frontRadius, *track ) );
428 else if( frontMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
429 m_frontCountersinkCutouts.Add( new FILLED_CIRCLE_2D( via_center, frontRadius, *track ) );
430 }
431
432 BVH_CONTAINER_2D *layerHoleContainer = m_layerHoleMap[layer];
433 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, frontRadius + thickness, *track ) );
434 }
435
436 const auto backMode = via->GetBackPostMachining().value_or( PAD_DRILL_POST_MACHINING_MODE::UNKNOWN );
437 const double backRadius = via->GetBackPostMachiningSize() * m_biuTo3Dunits / 2.0;
438
441 && backRadius > hole_inner_radius )
442 {
443
444 if( layer == layer_ids.back() ) // only add once for back layer
445 {
447 m_backCounterboreCutouts.Add( new FILLED_CIRCLE_2D( via_center, backRadius, *track ) );
448 else if( backMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
449 m_backCountersinkCutouts.Add( new FILLED_CIRCLE_2D( via_center, backRadius, *track ) );
450 }
451
452 BVH_CONTAINER_2D *layerHoleContainer = m_layerHoleMap[layer];
453 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, backRadius + thickness, *track ) );
454 }
455
456 // Add backdrill cutouts for vias - affects specific layers only
457 float backdrillRadius = via->GetSecondaryDrillSize().value_or( 0 ) * m_biuTo3Dunits / 2.0f ;
458
459 // Only add if backdrill is larger than original hole
460 if( backdrillRadius > hole_inner_radius + thickness )
461 {
462 PCB_LAYER_ID secStart = via->GetSecondaryDrillStartLayer();
463 PCB_LAYER_ID secEnd = via->GetSecondaryDrillEndLayer();
464
465 bool validLyPair = secStart >= 0 && secEnd >= 0;
466
467 if( validLyPair && LAYER_RANGE( secStart, secEnd, m_copperLayersCount ).Contains( layer ) )
468 {
469 // Add to layer hole map for this layer
470 BVH_CONTAINER_2D* layerHoleContainer = m_layerHoleMap[layer];
471
472 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, backdrillRadius, *track ) );
473 }
474
475 if( validLyPair && layer == secStart )
476 m_backdrillCutouts.Add( new FILLED_CIRCLE_2D( via_center, backdrillRadius, *track ) );
477 }
478
479 // Add tertiary drill cutouts for vias - affects specific layers only
480 float tertiaryDrillRadius = via->GetTertiaryDrillSize().value_or( 0 ) * m_biuTo3Dunits / 2.0f ;
481
482 // Only add if tertiary drill is larger than original hole
483 if( tertiaryDrillRadius > hole_inner_radius + thickness )
484 {
485 PCB_LAYER_ID terStart = via->GetTertiaryDrillStartLayer();
486 PCB_LAYER_ID terEnd = via->GetTertiaryDrillEndLayer();
487
488 bool validLyPair = terStart >= 0 && terEnd >= 0;
489
490 if( validLyPair && LAYER_RANGE( terStart, terEnd, m_copperLayersCount ).Contains( layer ) )
491 {
492 // Add to layer hole map for this layer
493 BVH_CONTAINER_2D* layerHoleContainer = m_layerHoleMap[layer];
494
495 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, tertiaryDrillRadius, *track ) );
496 }
497
498 if( validLyPair && layer == terStart )
499 m_tertiarydrillCutouts.Add( new FILLED_CIRCLE_2D( via_center, tertiaryDrillRadius, *track ) );
500 }
501 }
502
503 if( cfg.DifferentiatePlatedCopper() && layer == F_Cu )
504 {
506 ERROR_INSIDE );
507 }
508 else if( cfg.DifferentiatePlatedCopper() && layer == B_Cu )
509 {
511 ERROR_INSIDE );
512 }
513 }
514 }
515
516 // Create VIAS and THTs objects and add it to holes containers
517 for( PCB_LAYER_ID layer : layer_ids )
518 {
519 if( !m_layerHoleOdPolys.contains( layer ) )
520 {
522 }
523
524 if( !m_layerHoleIdPolys.contains( layer ) )
525 {
527 }
528
529 // ADD TRACKS
530 const unsigned int nTracks = trackList.size();
531
532 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
533 {
534 const PCB_TRACK *track = trackList[trackIdx];
535
536 if( !track->IsOnLayer( layer ) )
537 continue;
538
539 // ADD VIAS and THT
540 if( track->Type() == PCB_VIA_T )
541 {
542 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
543 const VIATYPE viatype = via->GetViaType();
544
545 // Add outer holes of VIAs
546 SHAPE_POLY_SET *layerOuterHolesPoly = nullptr;
547 SHAPE_POLY_SET *layerInnerHolesPoly = nullptr;
548
549 // found
550 wxASSERT( m_layerHoleOdPolys.contains( layer ) );
551 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
552
553 layerOuterHolesPoly = m_layerHoleOdPolys[layer];
554 layerInnerHolesPoly = m_layerHoleIdPolys[layer];
555
556 const int holediameter = via->GetDrillValue();
557 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
558
559 if( viatype != VIATYPE::THROUGH )
560 {
561 // Add PCB_VIA hole contours
562 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(), hole_outer_radius,
563 via->GetMaxError(), ERROR_INSIDE );
564
565 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(), holediameter / 2,
566 via->GetMaxError(), ERROR_INSIDE );
567 }
568 else if( layer == layer_ids[0] ) // it only adds once the THT holes
569 {
570 const int hole_outer_ring_radius = KiROUND( via->GetWidth( layer ) / 2.0 );
571
572 // Add through hole contours
573 TransformCircleToPolygon( m_TH_ODPolys, via->GetStart(), hole_outer_radius,
574 via->GetMaxError(), ERROR_INSIDE );
575
576 // Add same thing for vias only
577 TransformCircleToPolygon( m_viaTH_ODPolys, via->GetStart(), hole_outer_radius,
578 via->GetMaxError(), ERROR_INSIDE );
579
581 {
582 TransformCircleToPolygon( m_viaAnnuliPolys, via->GetStart(), hole_outer_ring_radius,
583 via->GetMaxError(), ERROR_INSIDE );
584 }
585 }
586
587 // Add counterbore/countersink polygons for vias
588 const auto frontMode = via->GetFrontPostMachining();
589
590 if( frontMode.has_value()
592 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
593 {
594 const int frontRadiusBIU = via->GetFrontPostMachiningSize() / 2;
595
596 if( frontRadiusBIU > holediameter / 2 )
597 {
598 int frontRadiusOuterBIU = frontRadiusBIU + GetHolePlatingThickness();
599
600 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
601 {
602 TransformCircleToPolygon( m_frontCounterborePolys, via->GetStart(), frontRadiusBIU,
603 via->GetMaxError(), ERROR_INSIDE );
604 }
605 else if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
606 {
607 TransformCircleToPolygon( m_frontCountersinkPolys, via->GetStart(), frontRadiusBIU,
608 via->GetMaxError(), ERROR_INSIDE );
609 }
610
611 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(), frontRadiusOuterBIU,
612 via->GetMaxError(), ERROR_INSIDE );
613 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(), frontRadiusBIU,
614 via->GetMaxError(), ERROR_INSIDE );
615 }
616 }
617
618 const auto backMode = via->GetBackPostMachining();
619
620 if( backMode.has_value()
622 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
623 {
624 const int backRadiusBIU = via->GetBackPostMachiningSize() / 2;
625
626 if( backRadiusBIU > holediameter / 2 )
627 {
628 int backRadiusOuterBIU = backRadiusBIU + GetHolePlatingThickness();
629
630 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
631 {
632 TransformCircleToPolygon( m_backCounterborePolys, via->GetStart(), backRadiusBIU,
633 via->GetMaxError(), ERROR_INSIDE );
634 }
635 else if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
636 {
637 TransformCircleToPolygon( m_backCountersinkPolys, via->GetStart(), backRadiusBIU,
638 via->GetMaxError(), ERROR_INSIDE );
639 }
640
641 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(), backRadiusOuterBIU,
642 via->GetMaxError(), ERROR_INSIDE );
643 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(), backRadiusBIU,
644 via->GetMaxError(), ERROR_INSIDE );
645 }
646 }
647
648 // Add backdrill polygons for vias - affects specific layers only
649 const auto secondaryDrillSize = via->GetSecondaryDrillSize();
650
651 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
652 {
653 const int backdrillRadiusBIU = secondaryDrillSize.value() / 2;
654 const int backdrillOuterRadiusBIU = backdrillRadiusBIU + GetHolePlatingThickness();
655 const int holeOuterRadiusBIU = hole_outer_radius;
656
657 // Only add if backdrill is larger than original hole outer diameter
658 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
659 {
660 PCB_LAYER_ID secStart = via->GetSecondaryDrillStartLayer();
661 PCB_LAYER_ID secEnd = via->GetSecondaryDrillEndLayer();
662 bool validLyPair = secStart >= 0 && secEnd >= 0;
663
664 // Iterate through layers affected by backdrill
665 if( validLyPair && LAYER_RANGE( secStart, secEnd, m_copperLayersCount ).Contains( layer ) )
666 {
667 TransformCircleToPolygon( *m_layerHoleOdPolys[layer], via->GetStart(),
668 backdrillOuterRadiusBIU, via->GetMaxError(), ERROR_INSIDE );
669
670 TransformCircleToPolygon( *m_layerHoleIdPolys[layer], via->GetStart(),
671 backdrillRadiusBIU, via->GetMaxError(), ERROR_INSIDE );
672
674 backdrillOuterRadiusBIU, via->GetMaxError(), ERROR_INSIDE );
675 }
676 }
677 }
678
679 // Add backdrill polygons for vias - affects specific layers only
680 const auto tertiaryDrillSize = via->GetTertiaryDrillSize();
681
682 if( tertiaryDrillSize.has_value() && tertiaryDrillSize.value() > 0 )
683 {
684 const int backdrillRadiusBIU = tertiaryDrillSize.value() / 2;
685 const int backdrillOuterRadiusBIU = backdrillRadiusBIU + GetHolePlatingThickness();
686 const int holeOuterRadiusBIU = hole_outer_radius;
687
688 // Only add if backdrill is larger than original hole outer diameter
689 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
690 {
691 PCB_LAYER_ID terStart = via->GetTertiaryDrillStartLayer();
692 PCB_LAYER_ID terEnd = via->GetTertiaryDrillEndLayer();
693 bool validLyPair = terStart >= 0 && terEnd >= 0;
694
695 if( validLyPair && LAYER_RANGE( terStart, terEnd, m_copperLayersCount ).Contains( layer ) )
696 {
697 PCB_LAYER_ID backdrillLayer = layer;
698
699 TransformCircleToPolygon( *m_layerHoleOdPolys[backdrillLayer], via->GetStart(),
700 backdrillOuterRadiusBIU, via->GetMaxError(), ERROR_INSIDE );
701
702 TransformCircleToPolygon( *m_layerHoleIdPolys[backdrillLayer], via->GetStart(),
703 backdrillRadiusBIU, via->GetMaxError(), ERROR_INSIDE );
704
706 backdrillOuterRadiusBIU, via->GetMaxError(), ERROR_INSIDE );
707 }
708 }
709 }
710 }
711 }
712 }
713
714 // Creates vertical outline contours of the tracks and add it to the poly of the layer
716 {
717 for( PCB_LAYER_ID layer : layer_ids )
718 {
719 wxASSERT( m_layers_poly.contains( layer ) );
720
721 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
722
723 // ADD TRACKS
724 unsigned int nTracks = trackList.size();
725
726 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
727 {
728 const PCB_TRACK *track = trackList[trackIdx];
729
730 if( !track->IsOnLayer( layer ) )
731 continue;
732
733 // Skip vias annulus when not flashed on this layer
734 if( track->Type() == PCB_VIA_T && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
735 continue;
736
737 // Add the track/via contour
738 track->TransformShapeToPolygon( *layerPoly, layer, 0, track->GetMaxError(), ERROR_INSIDE );
739 }
740 }
741 }
742
743 // Add holes of footprints
744 for( FOOTPRINT* footprint : m_board->Footprints() )
745 {
746 for( PAD* pad : footprint->Pads() )
747 {
748 // Note: holes of NPTH are already built by GetBoardPolygonOutlines
749 if( !pad->HasHole() )
750 continue;
751
752 m_holeCount++;
753 double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
754 m_averageHoleDiameter += static_cast<float>( holeDiameter * m_biuTo3Dunits );
755
756 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
757 {
758 // Ensure the silk drawings are clipped to the NPTH hole, like other pad/via holes
759 // even if the clip to board body is not activated (remember NPTH holes are part of
760 // the board body)
762 continue;
763 }
764
765 // The hole in the body is inflated by copper thickness
766 int inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
767
768 createPadHoleShape( pad, &m_TH_ODs, inflate );
769
771 createPadHoleShape( pad, &m_viaAnnuli, inflate );
772
774
775 // Add counterbore/countersink cutouts for pads
776 const float holeDiameterUnits = static_cast<float>( ( pad->GetDrillSize().x + pad->GetDrillSize().y )
777 / 2.0 * m_biuTo3Dunits );
778 const float holeInnerRadius = holeDiameterUnits / 2.0f;
779 const SFVEC2F padCenter( pad->GetPosition().x * static_cast<float>( m_biuTo3Dunits ),
780 -pad->GetPosition().y * static_cast<float>( m_biuTo3Dunits ) );
781
782 const auto frontMode = pad->GetFrontPostMachining();
783
784 if( frontMode.has_value()
786 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
787 {
788 float frontRadius = pad->GetFrontPostMachiningSize() * 0.5f * static_cast<float>( m_biuTo3Dunits );
789
790 if( frontRadius > holeInnerRadius )
791 {
792 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
793 {
794 m_frontCounterboreCutouts.Add( new FILLED_CIRCLE_2D( padCenter, frontRadius, *pad ) );
795 }
796 else if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
797 {
798 m_frontCountersinkCutouts.Add( new FILLED_CIRCLE_2D( padCenter, frontRadius, *pad ) );
799 }
800 }
801 }
802
803 const auto backMode = pad->GetBackPostMachining();
804
805 if( backMode.has_value()
807 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
808 {
809 float backRadius = pad->GetBackPostMachiningSize() * 0.5f * static_cast<float>( m_biuTo3Dunits );
810
811 if( backRadius > holeInnerRadius )
812 {
813 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
814 {
815 m_backCounterboreCutouts.Add( new FILLED_CIRCLE_2D( padCenter, backRadius, *pad ) );
816 }
817 else if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
818 {
819 m_backCountersinkCutouts.Add( new FILLED_CIRCLE_2D( padCenter, backRadius, *pad ) );
820 }
821 }
822 }
823
824 // Add backdrill cutouts for pads - affects specific layers only
825 const VECTOR2I& secDrillSize = pad->GetSecondaryDrillSize();
826
827 if( secDrillSize.x > 0 || secDrillSize.y > 0 )
828 {
829 const float backdrillRadius = ( secDrillSize.x + secDrillSize.y ) * 0.25f
830 * static_cast<float>( m_biuTo3Dunits );
831
832 // The hole outer diameter with plating
833 const float holeOuterRadius = holeInnerRadius
834 + static_cast<float>( GetHolePlatingThickness() * m_biuTo3Dunits );
835
836 // Only add if backdrill is larger than original hole outer diameter
837 if( backdrillRadius > holeOuterRadius )
838 {
839 PCB_LAYER_ID secStart = pad->GetSecondaryDrillStartLayer();
840 PCB_LAYER_ID secEnd = pad->GetSecondaryDrillEndLayer();
841 bool validLyPair = secStart >= 0 && secEnd >= 0;
842
843 // Iterate through layers affected by backdrill
844 if( validLyPair )
845 {
846 for( PCB_LAYER_ID backdrillLayer : LAYER_RANGE( secStart, secEnd, m_copperLayersCount ) )
847 {
848 // Add to layer hole map for this layer
849 BVH_CONTAINER_2D* layerHoleContainer = nullptr;
850
851 if( !m_layerHoleMap.contains( backdrillLayer ) )
852 {
853 layerHoleContainer = new BVH_CONTAINER_2D;
854 m_layerHoleMap[backdrillLayer] = layerHoleContainer;
855 }
856 else
857 {
858 layerHoleContainer = m_layerHoleMap[backdrillLayer];
859 }
860
861 layerHoleContainer->Add( new FILLED_CIRCLE_2D( padCenter, backdrillRadius, *pad ) );
862 }
863 }
864 }
865 }
866 }
867 }
868
869 if( m_holeCount )
871
872 // Add contours of the pad holes (pads can be Circle or Segment holes)
873 for( FOOTPRINT* footprint : m_board->Footprints() )
874 {
875 for( PAD* pad : footprint->Pads() )
876 {
877 if( !pad->HasHole() )
878 continue;
879
880 // The hole in the body is inflated by copper thickness.
881 const int inflate = GetHolePlatingThickness();
882
883 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
884 {
886 pad->TransformHoleToPolygon( m_viaAnnuliPolys, inflate, pad->GetMaxError(), ERROR_INSIDE );
887
888 pad->TransformHoleToPolygon( m_TH_ODPolys, inflate, pad->GetMaxError(), ERROR_INSIDE );
889 }
890 else
891 {
892 // If not plated, no copper.
894 pad->TransformHoleToPolygon( m_viaAnnuliPolys, 0, pad->GetMaxError(), ERROR_INSIDE );
895
896 pad->TransformHoleToPolygon( m_NPTH_ODPolys, 0, pad->GetMaxError(), ERROR_INSIDE );
897 }
898
899
900 // Add counterbore/countersink polygons for pads
901 const double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
902 const int holeRadius = KiROUND( holeDiameter / 2.0 );
903
904 const std::optional<PAD_DRILL_POST_MACHINING_MODE> frontMode = pad->GetFrontPostMachining();
905
906 if( frontMode.has_value()
908 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
909 {
910 const int frontRadiusBIU = pad->GetFrontPostMachiningSize() / 2;
911
912 if( frontRadiusBIU > holeRadius )
913 {
914 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
915 {
916 TransformCircleToPolygon( m_frontCounterborePolys, pad->GetPosition(), frontRadiusBIU,
917 pad->GetMaxError(), ERROR_INSIDE );
918 }
919 else if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
920 {
921 TransformCircleToPolygon( m_frontCountersinkPolys, pad->GetPosition(), frontRadiusBIU,
922 pad->GetMaxError(), ERROR_INSIDE );
923 }
924 }
925 }
926
927 const std::optional<PAD_DRILL_POST_MACHINING_MODE> backMode = pad->GetBackPostMachining();
928
929 if( backMode.has_value()
931 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
932 {
933 const int backRadiusBIU = pad->GetBackPostMachiningSize() / 2;
934
935 if( backRadiusBIU > holeRadius )
936 {
937 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
938 {
939 TransformCircleToPolygon( m_backCounterborePolys, pad->GetPosition(), backRadiusBIU,
940 pad->GetMaxError(), ERROR_INSIDE );
941 }
942 else if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
943 {
944 TransformCircleToPolygon( m_backCountersinkPolys, pad->GetPosition(), backRadiusBIU,
945 pad->GetMaxError(), ERROR_INSIDE );
946 }
947 }
948 }
949
950 // Add backdrill polygons for pads - affects specific layers only
951 const VECTOR2I& secDrillSize = pad->GetSecondaryDrillSize();
952
953 if( secDrillSize.x > 0 || secDrillSize.y > 0 )
954 {
955 const int backdrillRadiusBIU = ( secDrillSize.x + secDrillSize.y ) / 4;
956 const int holeOuterRadiusBIU = holeRadius + inflate;
957
958 // Only add if backdrill is larger than original hole outer diameter
959 if( backdrillRadiusBIU > holeOuterRadiusBIU )
960 {
961 PCB_LAYER_ID secStart = pad->GetSecondaryDrillStartLayer();
962 PCB_LAYER_ID secEnd = pad->GetSecondaryDrillEndLayer();
963 bool validLyPair = secStart >= 0 && secEnd >= 0;
964
965 if( validLyPair )
966 {
967 TransformCircleToPolygon( m_BackdrillPolys, pad->GetPosition(), backdrillRadiusBIU,
968 pad->GetMaxError(), ERROR_INSIDE );
969
970 // Iterate through layers affected by backdrill
971 for( PCB_LAYER_ID backdrillLayer : LAYER_RANGE( secStart, secEnd, m_copperLayersCount ) )
972 {
973 // Add polygon to per-layer hole polys
974 SHAPE_POLY_SET* layerHolePoly = nullptr;
975
976 if( !m_layerHoleOdPolys.contains( backdrillLayer ) )
977 {
978 layerHolePoly = new SHAPE_POLY_SET;
979 m_layerHoleOdPolys[backdrillLayer] = layerHolePoly;
980 }
981 else
982 {
983 layerHolePoly = m_layerHoleOdPolys[backdrillLayer];
984 }
985
986 TransformCircleToPolygon( *layerHolePoly, pad->GetPosition(), backdrillRadiusBIU,
987 pad->GetMaxError(), ERROR_INSIDE );
988 }
989 }
990 }
991 }
992 }
993 }
994
995 // Add footprints copper items (pads, shapes and text) to containers
996 for( PCB_LAYER_ID layer : layer_ids )
997 {
998 wxASSERT( m_layerMap.contains( layer ) );
999
1000 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
1001
1002 for( FOOTPRINT* fp : m_board->Footprints() )
1003 {
1004 addPads( fp, layerContainer, layer );
1005 addFootprintShapes( fp, layerContainer, layer, visibilityFlags );
1006
1007 // Add copper item to the plated copper polygon list if required
1008 if( cfg.DifferentiatePlatedCopper() && IsExternalCopperLayer( layer ) )
1009 {
1011
1012 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), ERROR_INSIDE );
1013 transformFPTextToPolySet( fp, layer, visibilityFlags, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1014 transformFPShapesToPolySet( fp, layer, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1015 }
1016
1017 // Add copper item to poly contours (vertical outlines) if required
1019 {
1020 wxASSERT( m_layers_poly.contains( layer ) );
1021
1022 SHAPE_POLY_SET* layerPoly = m_layers_poly[layer];
1023
1024 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), ERROR_INSIDE );
1025 transformFPTextToPolySet( fp, layer, visibilityFlags, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1026 transformFPShapesToPolySet( fp, layer, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1027 }
1028 }
1029 }
1030
1031 // Add graphic item on copper layers to object containers
1032 for( PCB_LAYER_ID layer : layer_ids )
1033 {
1034 wxASSERT( m_layerMap.contains( layer ) );
1035
1036 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
1037
1038 // Add graphic items on copper layers (texts and other graphics)
1039 for( BOARD_ITEM* item : m_board->Drawings() )
1040 {
1041 if( !item->IsOnLayer( layer ) )
1042 continue;
1043
1044 switch( item->Type() )
1045 {
1046 case PCB_SHAPE_T:
1047 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
1048 break;
1049
1050 case PCB_TEXT_T:
1051 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
1052 break;
1053
1054 case PCB_TEXTBOX_T:
1055 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
1056 break;
1057
1058 case PCB_TABLE_T:
1059 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
1060 break;
1061
1062 case PCB_BARCODE_T:
1063 addBarCode( static_cast<PCB_BARCODE*>( item ), layerContainer, item );
1064 break;
1065
1066 case PCB_DIM_ALIGNED_T:
1067 case PCB_DIM_CENTER_T:
1068 case PCB_DIM_RADIAL_T:
1070 case PCB_DIM_LEADER_T:
1071 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
1072 break;
1073
1074 case PCB_REFERENCE_IMAGE_T: // ignore
1075 break;
1076
1077 default:
1078 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), item->Type() );
1079 break;
1080 }
1081
1082 // Add copper item to the plated copper polygon list if required
1083 if( cfg.DifferentiatePlatedCopper() && IsExternalCopperLayer( layer ) )
1084 {
1086
1087 // Note: for TEXT and TEXTBOX, TransformShapeToPolygon returns the bounding
1088 // box shape, not the exact text shape. So it is not used for these items
1089 if( item->Type() == PCB_TEXTBOX_T )
1090 {
1091 PCB_TEXTBOX* text_box = static_cast<PCB_TEXTBOX*>( item );
1092 text_box->TransformTextToPolySet( *copperPolys, 0, text_box->GetMaxError(), ERROR_INSIDE );
1093
1094 // Add box outlines
1095 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, text_box->GetMaxError(),
1096 ERROR_INSIDE );
1097 }
1098 else if( item->Type() == PCB_TEXT_T )
1099 {
1100 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1101 text->TransformTextToPolySet( *copperPolys, 0, text->GetMaxError(), ERROR_INSIDE );
1102 }
1103 else if( item->Type() != PCB_REFERENCE_IMAGE_T )
1104 {
1105 item->TransformShapeToPolySet( *copperPolys, layer, 0, item->GetMaxError(), ERROR_INSIDE );
1106 }
1107 }
1108
1109 // Add copper item to poly contours (vertical outlines) if required
1111 {
1112 wxASSERT( m_layers_poly.contains( layer ) );
1113
1114 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
1115
1116 switch( item->Type() )
1117 {
1118 case PCB_SHAPE_T:
1119 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), ERROR_INSIDE );
1120 break;
1121
1122 case PCB_TEXT_T:
1123 {
1124 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1125
1126 text->TransformTextToPolySet( *layerPoly, 0, text->GetMaxError(), ERROR_INSIDE );
1127 break;
1128 }
1129
1130 case PCB_TEXTBOX_T:
1131 {
1132 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
1133
1134 if( textbox->IsBorderEnabled() )
1135 {
1136 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->GetMaxError(),
1137 ERROR_INSIDE );
1138 }
1139
1140 textbox->TransformTextToPolySet( *layerPoly, 0, textbox->GetMaxError(), ERROR_INSIDE );
1141 break;
1142 }
1143
1144 case PCB_TABLE_T:
1145 {
1146 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
1147
1148 for( PCB_TABLECELL* cell : table->GetCells() )
1149 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), ERROR_INSIDE );
1150
1151 table->DrawBorders(
1152 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
1153 const STROKE_PARAMS& stroke )
1154 {
1155 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
1156 seg.TransformToPolygon( *layerPoly, table->GetMaxError(), ERROR_INSIDE );
1157 } );
1158 break;
1159 }
1160
1161 case PCB_BARCODE_T:
1162 {
1163 PCB_BARCODE* bar_code = static_cast<PCB_BARCODE*>( item );
1164
1165 bar_code->TransformShapeToPolySet( *layerPoly, layer, 0, 0, ERROR_INSIDE );
1166 break;
1167 }
1168
1169 case PCB_DIM_ALIGNED_T:
1170 case PCB_DIM_CENTER_T:
1171 case PCB_DIM_RADIAL_T:
1173 case PCB_DIM_LEADER_T:
1174 {
1175 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
1176
1177 dimension->TransformTextToPolySet( *layerPoly, 0, dimension->GetMaxError(), ERROR_INSIDE );
1178
1179 for( const std::shared_ptr<SHAPE>& shape : dimension->GetShapes() )
1180 shape->TransformToPolygon( *layerPoly, dimension->GetMaxError(), ERROR_INSIDE );
1181
1182 break;
1183 }
1184
1185 case PCB_REFERENCE_IMAGE_T: // ignore
1186 break;
1187
1188 default:
1189 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), item->Type() );
1190 break;
1191 }
1192 }
1193 }
1194 }
1195
1196 if( cfg.show_zones )
1197 {
1198 if( aStatusReporter )
1199 aStatusReporter->Report( _( "Create zones" ) );
1200
1201 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
1202 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
1203
1204 for( ZONE* zone : m_board->Zones() )
1205 {
1206 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
1207 {
1208 zones.emplace_back( std::make_pair( zone, layer ) );
1209 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
1210
1211 if( cfg.DifferentiatePlatedCopper() && IsExternalCopperLayer( layer ) )
1212 {
1214
1215 zone->TransformShapeToPolygon( *copperPolys, layer, 0, zone->GetMaxError(), ERROR_INSIDE );
1216 }
1217 }
1218 }
1219
1220 // Add zones objects
1221 std::atomic<size_t> nextZone( 0 );
1222 std::atomic<size_t> threadsFinished( 0 );
1223
1224 size_t parallelThreadCount = std::min<size_t>( zones.size(),
1225 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
1226
1227 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1228 {
1229 std::thread t = std::thread( [&]()
1230 {
1231 for( size_t areaId = nextZone.fetch_add( 1 );
1232 areaId < zones.size();
1233 areaId = nextZone.fetch_add( 1 ) )
1234 {
1235 ZONE* zone = zones[areaId].first;
1236
1237 if( zone == nullptr )
1238 break;
1239
1240 PCB_LAYER_ID layer = zones[areaId].second;
1241
1242 if( m_layerMap.contains( layer ) )
1243 addSolidAreasShapes( zone, m_layerMap[layer], layer );
1244
1246 && m_layers_poly.contains( layer ) )
1247 {
1248 auto mut_it = layer_lock.find( layer );
1249
1250 if( mut_it != layer_lock.end() )
1251 {
1252 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
1253 zone->TransformSolidAreasShapesToPolygon( layer, *m_layers_poly[layer] );
1254 }
1255 }
1256 }
1257
1258 threadsFinished++;
1259 } );
1260
1261 t.detach();
1262 }
1263
1264 while( threadsFinished < parallelThreadCount )
1265 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1266 }
1267 // End Build Copper layers
1268
1269 // This will make a union of all added contours
1270 m_TH_ODPolys.Simplify();
1271 m_NPTH_ODPolys.Simplify();
1272 m_viaTH_ODPolys.Simplify();
1273 m_viaAnnuliPolys.Simplify();
1274
1275 m_frontCounterborePolys.Simplify();
1276 m_backCounterborePolys.Simplify();
1277 m_frontCountersinkPolys.Simplify();
1278 m_backCountersinkPolys.Simplify();
1279
1280 // Remove counterbore/countersink/backdrill cutouts from via annuli (both front and back)
1281 // The via annuli are used for silkscreen clipping and shouldn't include areas removed
1282 // by counterbore, countersink, or backdrill operations
1283 if( m_viaAnnuliPolys.OutlineCount() > 0 )
1284 {
1285 if( m_frontCounterborePolys.OutlineCount() > 0 )
1286 m_viaAnnuliPolys.BooleanSubtract( m_frontCounterborePolys );
1287
1288 if( m_backCounterborePolys.OutlineCount() > 0 )
1289 m_viaAnnuliPolys.BooleanSubtract( m_backCounterborePolys );
1290
1291 if( m_frontCountersinkPolys.OutlineCount() > 0 )
1292 m_viaAnnuliPolys.BooleanSubtract( m_frontCountersinkPolys );
1293
1294 if( m_backCountersinkPolys.OutlineCount() > 0 )
1295 m_viaAnnuliPolys.BooleanSubtract( m_backCountersinkPolys );
1296
1297 if( m_BackdrillPolys.OutlineCount() > 0 )
1298 m_viaAnnuliPolys.BooleanSubtract( m_BackdrillPolys );
1299
1300 if( m_TertiarydrillPolys.OutlineCount() > 0 )
1301 m_viaAnnuliPolys.BooleanSubtract( m_TertiarydrillPolys );
1302 }
1303
1304 // Build Tech layers
1305 // Based on:
1306 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
1307 if( aStatusReporter )
1308 aStatusReporter->Report( _( "Build Tech layers" ) );
1309
1310 // draw graphic items, on technical layers
1311
1312 LSEQ techLayerList = LSET::AllNonCuMask().Seq( {
1313 B_Adhes,
1314 F_Adhes,
1315 B_Paste,
1316 F_Paste,
1317 B_SilkS,
1318 F_SilkS,
1319 B_Mask,
1320 F_Mask,
1321
1322 // Aux Layers
1323 Dwgs_User,
1324 Cmts_User,
1325 Eco1_User,
1326 Eco2_User,
1327 User_1,
1328 User_2,
1329 User_3,
1330 User_4,
1331 User_5,
1332 User_6,
1333 User_7,
1334 User_8,
1335 User_9,
1336 User_10,
1337 User_11,
1338 User_12,
1339 User_13,
1340 User_14,
1341 User_15,
1342 User_16,
1343 User_17,
1344 User_18,
1345 User_19,
1346 User_20,
1347 User_21,
1348 User_22,
1349 User_23,
1350 User_24,
1351 User_25,
1352 User_26,
1353 User_27,
1354 User_28,
1355 User_29,
1356 User_30,
1357 User_31,
1358 User_32,
1359 User_33,
1360 User_34,
1361 User_35,
1362 User_36,
1363 User_37,
1364 User_38,
1365 User_39,
1366 User_40,
1367 User_41,
1368 User_42,
1369 User_43,
1370 User_44,
1371 User_45,
1372 } );
1373
1374 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
1375
1377 {
1378 enabledFlags.set( LAYER_3D_SOLDERMASK_TOP );
1379 enabledFlags.set( LAYER_3D_SOLDERMASK_BOTTOM );
1380 }
1381
1382 for( PCB_LAYER_ID layer : techLayerList )
1383 {
1384 if( aStatusReporter )
1385 aStatusReporter->Report( wxString::Format( _( "Build Tech layer %d" ), (int) layer ) );
1386
1387 if( !Is3dLayerEnabled( layer, enabledFlags ) )
1388 continue;
1389
1390 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
1391 m_layerMap[layer] = layerContainer;
1392
1393 SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
1394 m_layers_poly[layer] = layerPoly;
1395
1396 if( Is3dLayerEnabled( layer, visibilityFlags ) )
1397 {
1398 // Add drawing objects
1399 for( BOARD_ITEM* item : m_board->Drawings() )
1400 {
1401 if( !item->IsOnLayer( layer ) )
1402 continue;
1403
1404 switch( item->Type() )
1405 {
1406 case PCB_SHAPE_T:
1407 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
1408 break;
1409
1410 case PCB_TEXT_T:
1411 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
1412 break;
1413
1414 case PCB_TEXTBOX_T:
1415 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
1416 break;
1417
1418 case PCB_TABLE_T:
1419 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
1420 break;
1421
1422 case PCB_BARCODE_T:
1423 addBarCode( static_cast<PCB_BARCODE*>( item ), layerContainer, item );
1424 break;
1425
1426 case PCB_DIM_ALIGNED_T:
1427 case PCB_DIM_CENTER_T:
1428 case PCB_DIM_RADIAL_T:
1430 case PCB_DIM_LEADER_T:
1431 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
1432 break;
1433
1434 default:
1435 break;
1436 }
1437 }
1438
1439 // Add track, via and arc tech layers
1440 if( IsSolderMaskLayer( layer ) )
1441 {
1442 for( PCB_TRACK* track : m_board->Tracks() )
1443 {
1444 if( !track->IsOnLayer( layer ) )
1445 continue;
1446
1447 // Only vias on a external copper layer can have a solder mask
1448 PCB_LAYER_ID copper_layer = ( layer == F_Mask ) ? F_Cu : B_Cu;
1449
1450 if( track->Type() == PCB_VIA_T )
1451 {
1452 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1453
1454 if( !via->FlashLayer( copper_layer ) )
1455 continue;
1456 }
1457
1458 int maskExpansion = track->GetSolderMaskExpansion();
1459 createTrackWithMargin( track, layerContainer, layer, maskExpansion );
1460 }
1461 }
1462
1463 // Add footprints tech layers - objects. Paste, mask, silk and fab belong to the
1464 // board fabrication outputs and render for every footprint, matching the gerber
1465 // plotters. DNP affects only the 3D model, handled by IsFootprintShown().
1466 for( FOOTPRINT* footprint : m_board->Footprints() )
1467 {
1468 if( layer == F_SilkS || layer == B_SilkS )
1469 {
1470 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
1471
1472 for( PAD* pad : footprint->Pads() )
1473 {
1474 if( !pad->IsOnLayer( layer ) )
1475 continue;
1476
1477 buildPadOutlineAsSegments( pad, layer, layerContainer, linewidth );
1478 }
1479 }
1480 else
1481 {
1482 addPads( footprint, layerContainer, layer );
1483 }
1484
1485 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
1486 }
1487
1488 // Draw non copper zones
1489 if( cfg.show_zones )
1490 {
1491 for( ZONE* zone : m_board->Zones() )
1492 {
1493 if( zone->IsOnLayer( layer ) )
1494 addSolidAreasShapes( zone, layerContainer, layer );
1495 }
1496 }
1497 }
1498
1499 // Add item contours. We need these if we're building vertical walls or if this is a
1500 // mask layer and we're differentiating copper from plated copper.
1502 || ( cfg.DifferentiatePlatedCopper() && IsSolderMaskLayer( layer ) ) )
1503 {
1504 // DRAWINGS
1505 for( BOARD_ITEM* item : m_board->Drawings() )
1506 {
1507 if( !item->IsOnLayer( layer ) )
1508 continue;
1509
1510 switch( item->Type() )
1511 {
1512 case PCB_SHAPE_T:
1513 {
1514 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
1515 int margin = 0;
1516
1517 if( IsSolderMaskLayer( layer ) && shape->HasSolderMask() )
1518 margin = shape->GetSolderMaskExpansion();
1519
1520 item->TransformShapeToPolySet( *layerPoly, layer, margin, item->GetMaxError(), ERROR_INSIDE );
1521 break;
1522 }
1523
1524 case PCB_TEXT_T:
1525 {
1526 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1527
1528 text->TransformTextToPolySet( *layerPoly, 0, text->GetMaxError(), ERROR_INSIDE );
1529 break;
1530 }
1531
1532 case PCB_TEXTBOX_T:
1533 {
1534 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
1535
1536 if( textbox->IsBorderEnabled() )
1537 {
1538 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->GetMaxError(),
1539 ERROR_INSIDE );
1540 }
1541
1542 textbox->TransformTextToPolySet( *layerPoly, 0, textbox->GetMaxError(), ERROR_INSIDE );
1543 break;
1544 }
1545
1546 case PCB_TABLE_T:
1547 {
1548 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
1549
1550 for( PCB_TABLECELL* cell : table->GetCells() )
1551 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), ERROR_INSIDE );
1552
1553 table->DrawBorders(
1554 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
1555 const STROKE_PARAMS& stroke )
1556 {
1557 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
1558 seg.TransformToPolygon( *layerPoly, table->GetMaxError(), ERROR_INSIDE );
1559 } );
1560
1561 break;
1562 }
1563
1564 case PCB_BARCODE_T:
1565 {
1566 PCB_BARCODE* bar_code = static_cast<PCB_BARCODE*>( item );
1567
1568 bar_code->TransformShapeToPolySet( *layerPoly, layer, 0, 0, ERROR_INSIDE );
1569 break;
1570 }
1571
1572 default:
1573 break;
1574 }
1575 }
1576
1577 // NON-TENTED VIAS
1578 if( ( layer == F_Mask || layer == B_Mask ) )
1579 {
1580 int maskExpansion = GetBoard()->GetDesignSettings().m_SolderMaskExpansion;
1581
1582 for( PCB_TRACK* track : m_board->Tracks() )
1583 {
1584 if( track->Type() == PCB_VIA_T )
1585 {
1586 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1587
1588 if( via->FlashLayer( layer ) && !via->IsTented( layer ) )
1589 {
1590 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1591 ERROR_INSIDE );
1592 }
1593 }
1594 else
1595 {
1596 if( track->HasSolderMask() )
1597 {
1598 track->TransformShapeToPolySet( *layerPoly, layer, maskExpansion, track->GetMaxError(),
1599 ERROR_INSIDE );
1600 }
1601 }
1602 }
1603 }
1604
1605 // FOOTPRINT CHILDREN
1606 for( FOOTPRINT* footprint : m_board->Footprints() )
1607 {
1608 if( layer == F_SilkS || layer == B_SilkS )
1609 {
1610 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
1611
1612 for( PAD* pad : footprint->Pads() )
1613 {
1614 if( pad->IsOnLayer( layer ) )
1615 {
1616 buildPadOutlineAsPolygon( pad, layer, *layerPoly, linewidth, pad->GetMaxError(),
1617 ERROR_INSIDE );
1618 }
1619 }
1620 }
1621 else
1622 {
1623 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, footprint->GetMaxError(), ERROR_INSIDE );
1624 }
1625
1626 transformFPTextToPolySet( footprint, layer, visibilityFlags, *layerPoly, footprint->GetMaxError(),
1627 ERROR_INSIDE );
1628 transformFPShapesToPolySet( footprint, layer, *layerPoly, footprint->GetMaxError(), ERROR_INSIDE );
1629 }
1630
1631 if( cfg.show_zones || layer == F_Mask || layer == B_Mask )
1632 {
1633 for( ZONE* zone : m_board->Zones() )
1634 {
1635 if( zone->IsOnLayer( layer ) )
1636 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1637 }
1638 }
1639
1640 // This will make a union of all added contours
1641 layerPoly->Simplify();
1642 }
1643 }
1644 // End Build Tech layers
1645
1646 // If we're rendering off-board silk, also render pads of footprints which are entirely
1647 // outside the board outline. This makes off-board footprints more visually recognizable.
1648 if( cfg.show_off_board_silk )
1649 {
1650 BOX2I boardBBox = m_board_poly.BBox();
1651
1652 for( FOOTPRINT* footprint : m_board->Footprints() )
1653 {
1654 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1655 {
1656 if( footprint->IsFlipped() )
1657 addPads( footprint, m_offboardPadsBack, B_Cu );
1658 else
1659 addPads( footprint, m_offboardPadsFront, F_Cu );
1660 }
1661 }
1662
1663 m_offboardPadsFront->BuildBVH();
1664 m_offboardPadsBack->BuildBVH();
1665 }
1666
1667 // Simplify layer polygons
1668
1669 if( aStatusReporter )
1670 aStatusReporter->Report( _( "Simplifying copper layer polygons" ) );
1671
1672 if( cfg.DifferentiatePlatedCopper() )
1673 {
1674 if( aStatusReporter )
1675 aStatusReporter->Report( _( "Calculating plated copper" ) );
1676
1677 // TRIM PLATED COPPER TO SOLDERMASK
1678 if( m_layers_poly.contains( F_Mask ) )
1679 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( F_Mask ) );
1680
1681 if( m_layers_poly.contains( B_Mask ))
1682 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( B_Mask ) );
1683
1684 // Subtract plated copper from unplated copper
1685 if( m_layers_poly.contains( F_Cu ) )
1686 m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys );
1687
1688 if( m_layers_poly.contains( B_Cu ) )
1689 m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys );
1690
1691 // ADD PLATED COPPER
1694
1697
1698 m_platedPadsFront->BuildBVH();
1699 m_platedPadsBack->BuildBVH();
1700 }
1701
1703 {
1704 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1705 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1706
1707 if( cfg.DifferentiatePlatedCopper() )
1708 {
1709 layer_id_without_F_and_B.clear();
1710 layer_id_without_F_and_B.reserve( layer_ids.size() );
1711
1712 for( PCB_LAYER_ID layer: layer_ids )
1713 {
1714 if( layer != F_Cu && layer != B_Cu )
1715 layer_id_without_F_and_B.push_back( layer );
1716 }
1717
1718 selected_layer_id = layer_id_without_F_and_B;
1719 }
1720
1721 if( selected_layer_id.size() > 0 )
1722 {
1723 if( aStatusReporter )
1724 {
1725 aStatusReporter->Report( wxString::Format( _( "Simplifying %d copper layers" ),
1726 (int) selected_layer_id.size() ) );
1727 }
1728
1729 std::atomic<size_t> nextItem( 0 );
1730 std::atomic<size_t> threadsFinished( 0 );
1731
1732 size_t parallelThreadCount = std::min<size_t>(
1733 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1734 selected_layer_id.size() );
1735
1736 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1737 {
1738 std::thread t = std::thread(
1739 [&nextItem, &threadsFinished, &selected_layer_id, this]()
1740 {
1741 for( size_t i = nextItem.fetch_add( 1 );
1742 i < selected_layer_id.size();
1743 i = nextItem.fetch_add( 1 ) )
1744 {
1745 if( m_layers_poly.contains( selected_layer_id[i] ) )
1746 {
1747 // This will make a union of all added contours
1748 m_layers_poly[ selected_layer_id[i] ]->ClearArcs();
1749 m_layers_poly[ selected_layer_id[i] ]->Simplify();
1750 }
1751 }
1752
1753 threadsFinished++;
1754 } );
1755
1756 t.detach();
1757 }
1758
1759 while( threadsFinished < parallelThreadCount )
1760 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1761 }
1762 }
1763
1764 // Simplify holes polygon contours
1765 if( aStatusReporter )
1766 aStatusReporter->Report( _( "Simplify holes contours" ) );
1767
1768 for( PCB_LAYER_ID layer : layer_ids )
1769 {
1770 if( m_layerHoleOdPolys.contains( layer ) )
1771 {
1772 // found
1773 SHAPE_POLY_SET *polyLayer = m_layerHoleOdPolys[layer];
1774 polyLayer->Simplify();
1775
1776 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
1777
1778 polyLayer = m_layerHoleIdPolys[layer];
1779 polyLayer->Simplify();
1780 }
1781 }
1782
1783 // Build BVH (Bounding volume hierarchy) for holes and vias
1784
1785 if( aStatusReporter )
1786 aStatusReporter->Report( _( "Build BVH for holes and vias" ) );
1787
1788 m_TH_IDs.BuildBVH();
1789 m_TH_ODs.BuildBVH();
1790 m_viaAnnuli.BuildBVH();
1791
1792 m_frontCounterboreCutouts.BuildBVH();
1793 m_backCounterboreCutouts.BuildBVH();
1794 m_frontCountersinkCutouts.BuildBVH();
1795 m_backCountersinkCutouts.BuildBVH();
1796 m_backdrillCutouts.BuildBVH();
1797 m_tertiarydrillCutouts.BuildBVH();
1798
1799 if( !m_layerHoleMap.empty() )
1800 {
1801 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1802 hole.second->BuildBVH();
1803 }
1804
1805 // We only need the Solder mask to initialize the BVH
1806 // because..?
1807 if( m_layerMap[B_Mask] )
1808 m_layerMap[B_Mask]->BuildBVH();
1809
1810 if( m_layerMap[F_Mask] )
1811 m_layerMap[F_Mask]->BuildBVH();
1812}
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_INSIDE
@ LAYER_CLASS_SILK
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
MAP_CONTAINER_2D_BASE m_layerHoleMap
Holes for each layer.
BVH_CONTAINER_2D m_backdrillCutouts
Backdrill cutouts.
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
BVH_CONTAINER_2D * m_offboardPadsBack
BVH_CONTAINER_2D m_frontCounterboreCutouts
Counterbore cutouts on front (top)
SHAPE_POLY_SET m_TertiarydrillPolys
Board tertiary drill polygons F.Cu->in.
void createLayers(REPORTER *aStatusReporter)
SHAPE_POLY_SET m_backCounterborePolys
Counterbore outer diameters on back.
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
BVH_CONTAINER_2D m_frontCountersinkCutouts
Countersink cutouts on front (top)
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)
void addSolidAreasShapes(const ZONE *aZone, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
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
SHAPE_POLY_SET m_board_poly
Board outline polygon.
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.
SHAPE_POLY_SET m_frontCounterborePolys
Counterbore outer diameters on front.
BVH_CONTAINER_2D m_tertiarydrillCutouts
Tertiary drill cutouts.
float m_averageHoleDiameter
SHAPE_POLY_SET m_viaTH_ODPolys
Via hole outer diameters.
void addBarCode(const PCB_BARCODE *aBarCode, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM *aOwner)
SHAPE_POLY_SET m_BackdrillPolys
Board backdrill polygons B.Cu->in.
const BOARD * GetBoard() const noexcept
BVH_CONTAINER_2D * m_platedPadsBack
void buildPadOutlineAsSegments(const PAD *aPad, PCB_LAYER_ID aLayer, CONTAINER_2D_BASE *aDstContainer, int aWidth)
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)
void createPadHoleShape(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aInflateValue)
SHAPE_POLY_SET m_frontCountersinkPolys
Countersink outer diameters on front.
unsigned int m_holeCount
BVH_CONTAINER_2D m_viaAnnuli
List of via annular rings.
unsigned int m_copperLayersCount
BVH_CONTAINER_2D m_backCountersinkCutouts
Countersink cutouts on back (bottom)
BVH_CONTAINER_2D m_backCounterboreCutouts
Counterbore cutouts on back (bottom)
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.
SHAPE_POLY_SET m_backCountersinkPolys
Countersink outer diameters on back.
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:83
virtual void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const
Convert the item shape to a polyset.
Definition board_item.h:511
int GetMaxError() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1158
void Add(OBJECT_2D *aObject)
static DELETED_BOARD_ITEM * GetInstance()
Definition board_item.h:579
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
DRAWINGS & GraphicalItems()
Definition footprint.h:378
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:623
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
Definition pad.h:61
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:202
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:287
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1194
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1831
Abstract dimension API.
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
bool HasSolderMask() const
Definition pcb_shape.h:329
int GetSolderMaskExpansion() const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
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:770
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.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:72
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:101
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 Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
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.
int GetWidth() const
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void TransformSolidAreasShapesToPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer) const
Convert solid areas full shapes to polygon set (the full shape is the polygon area with a thick outli...
Definition zone.cpp:1937
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:754
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:566
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:565
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition layer_ids.h:262
@ LAYER_FP_TEXT
Definition layer_ids.h:236
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition layer_ids.h:259
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:694
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ User_16
Definition layer_ids.h:135
@ User_29
Definition layer_ids.h:148
@ User_40
Definition layer_ids.h:159
@ User_15
Definition layer_ids.h:134
@ User_8
Definition layer_ids.h:127
@ User_11
Definition layer_ids.h:130
@ User_25
Definition layer_ids.h:144
@ User_34
Definition layer_ids.h:153
@ User_45
Definition layer_ids.h:164
@ B_Adhes
Definition layer_ids.h:99
@ User_36
Definition layer_ids.h:155
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ Cmts_User
Definition layer_ids.h:104
@ User_6
Definition layer_ids.h:125
@ User_7
Definition layer_ids.h:126
@ User_19
Definition layer_ids.h:138
@ User_23
Definition layer_ids.h:142
@ F_Adhes
Definition layer_ids.h:98
@ User_41
Definition layer_ids.h:160
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ User_14
Definition layer_ids.h:133
@ User_39
Definition layer_ids.h:158
@ User_5
Definition layer_ids.h:124
@ User_20
Definition layer_ids.h:139
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ User_42
Definition layer_ids.h:161
@ User_43
Definition layer_ids.h:162
@ B_Paste
Definition layer_ids.h:101
@ User_10
Definition layer_ids.h:129
@ User_9
Definition layer_ids.h:128
@ User_27
Definition layer_ids.h:146
@ User_28
Definition layer_ids.h:147
@ F_SilkS
Definition layer_ids.h:96
@ Eco2_User
Definition layer_ids.h:106
@ User_35
Definition layer_ids.h:154
@ User_31
Definition layer_ids.h:150
@ User_3
Definition layer_ids.h:122
@ User_1
Definition layer_ids.h:120
@ User_12
Definition layer_ids.h:131
@ B_SilkS
Definition layer_ids.h:97
@ User_30
Definition layer_ids.h:149
@ User_37
Definition layer_ids.h:156
@ User_22
Definition layer_ids.h:141
@ User_38
Definition layer_ids.h:157
@ User_4
Definition layer_ids.h:123
@ User_21
Definition layer_ids.h:140
@ User_24
Definition layer_ids.h:143
@ User_13
Definition layer_ids.h:132
@ User_2
Definition layer_ids.h:121
@ User_17
Definition layer_ids.h:136
@ User_33
Definition layer_ids.h:152
@ User_26
Definition layer_ids.h:145
@ User_32
Definition layer_ids.h:151
@ User_18
Definition layer_ids.h:137
@ User_44
Definition layer_ids.h:163
@ F_Cu
Definition layer_ids.h:60
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
BARCODE class definition.
VIATYPE
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...
std::string path
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:81
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:99
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:96
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:90
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:97
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:86
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:82
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:94
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:95
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:87
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:98
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
glm::vec2 SFVEC2F
Definition xv3d_types.h:38