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->Type() == PCB_SHAPE_T
82 || item->Type() == PCB_BARCODE_T
83 || BaseType( item->Type() ) == PCB_DIMENSION_T )
84 {
85 if( item->GetLayer() == aLayer )
86 item->TransformShapeToPolySet( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
87 }
88 }
89}
90
91
92void transformFPTextToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
93 const std::bitset<LAYER_3D_END>& aFlags, SHAPE_POLY_SET& aBuffer,
94 int aMaxError, ERROR_LOC aErrorLoc )
95{
96 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
97 {
98 if( item->GetLayer() != aLayer )
99 continue;
100
101 if( item->Type() == PCB_TEXT_T )
102 {
103 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
104
105 if( !aFlags.test( LAYER_FP_TEXT ) )
106 continue;
107
108 if( text->GetText() == wxT( "${REFERENCE}" ) && !aFlags.test( LAYER_FP_REFERENCES ) )
109 continue;
110
111 if( text->GetText() == wxT( "${VALUE}" ) && !aFlags.test( LAYER_FP_VALUES ) )
112 continue;
113
114 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer )
115 text->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
116 }
117
118 if( item->Type() == PCB_TEXTBOX_T )
119 {
120 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
121
122 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer )
123 {
124 // border
125 if( textbox->IsBorderEnabled() )
126 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
127
128 // text
129 textbox->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
130 }
131 }
132 }
133
134 for( const PCB_FIELD* field : aFootprint->GetFields() )
135 {
136 if( !aFlags.test( LAYER_FP_TEXT ) )
137 continue;
138
139 wxCHECK2( field, continue );
140
141 if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) )
142 continue;
143
144 if( field->IsValue() && !aFlags.test( LAYER_FP_VALUES ) )
145 continue;
146
147 if( field->GetLayer() == aLayer && field->IsVisible() )
148 field->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
149 }
150}
151
152
154{
155#define DELETE_AND_FREE( ptr ) \
156 { \
157 delete ptr; \
158 ptr = nullptr; \
159 } \
160
161#define DELETE_AND_FREE_MAP( map ) \
162 { \
163 for( auto& [ layer, poly ] : map ) \
164 delete poly; \
165 \
166 map.clear(); \
167 }
168
170
173
176
177 m_NPTH_ODPolys.RemoveAllContours();
178 m_TH_ODPolys.RemoveAllContours();
179 m_viaTH_ODPolys.RemoveAllContours();
180 m_viaAnnuliPolys.RemoveAllContours();
181
182 m_frontCounterborePolys.RemoveAllContours();
183 m_backCounterborePolys.RemoveAllContours();
184 m_frontCountersinkPolys.RemoveAllContours();
185 m_backCountersinkPolys.RemoveAllContours();
186
189
194
195 m_TH_ODs.Clear();
196 m_TH_IDs.Clear();
197 m_viaAnnuli.Clear();
198 m_viaTH_ODs.Clear();
199
204 m_backdrillCutouts.Clear();
206}
207
208
209void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
210{
212
213 // Build Copper layers
214 // Based on:
215 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
216
217#ifdef PRINT_STATISTICS_3D_VIEWER
218 int64_t stats_startCopperLayersTime = GetRunningMicroSecs();
219
220 int64_t start_Time = stats_startCopperLayersTime;
221#endif
222
224
225 std::bitset<LAYER_3D_END> visibilityFlags = GetVisibleLayers();
226
227 m_trackCount = 0;
229 m_viaCount = 0;
231 m_holeCount = 0;
233
234 if( !m_board )
235 return;
236
237 // Prepare track list, convert in a vector. Calc statistic for the holes
238 std::vector<const PCB_TRACK*> trackList;
239 trackList.clear();
240 trackList.reserve( m_board->Tracks().size() );
241
242 for( PCB_TRACK* track : m_board->Tracks() )
243 {
244 // Skip tracks (not vias theyt are on more than one layer ) on disabled layers
245 if( track->Type() != PCB_VIA_T && !Is3dLayerEnabled( track->GetLayer(), visibilityFlags ) )
246 {
247 continue;
248 }
249
250 // Note: a PCB_TRACK holds normal segment tracks and also vias circles (that have also
251 // drill values)
252 trackList.push_back( track );
253
254 if( track->Type() == PCB_VIA_T )
255 {
256 const PCB_VIA *via = static_cast< const PCB_VIA*>( track );
257 m_viaCount++;
258 m_averageViaHoleDiameter += static_cast<float>( via->GetDrillValue() * m_biuTo3Dunits );
259 }
260 else
261 {
262 m_trackCount++;
263 m_averageTrackWidth += static_cast<float>( track->GetWidth() * m_biuTo3Dunits );
264 }
265 }
266
267 if( m_trackCount )
269
270 if( m_viaCount )
272
273 // Prepare copper layers index and containers
274 std::vector<PCB_LAYER_ID> layer_ids;
275 layer_ids.clear();
276 layer_ids.reserve( m_copperLayersCount );
277
279 {
280 if( !Is3dLayerEnabled( layer, visibilityFlags ) ) // Skip non enabled layers
281 continue;
282
283 layer_ids.push_back( layer );
284
285 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
286 m_layerMap[layer] = layerContainer;
287
289 {
290 SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
291 m_layers_poly[layer] = layerPoly;
292 }
293 }
294
295 if( cfg.DifferentiatePlatedCopper() )
296 {
299
302 }
303
304 if( cfg.show_off_board_silk )
305 {
308 }
309
310 if( aStatusReporter )
311 aStatusReporter->Report( _( "Create tracks and vias" ) );
312
313 // Create tracks as objects and add it to container
314 for( PCB_LAYER_ID layer : layer_ids )
315 {
316 wxASSERT( m_layerMap.contains( layer ) );
317
318 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
319
320 for( const PCB_TRACK* track : trackList )
321 {
322 // NOTE: Vias can be on multiple layers
323 if( !track->IsOnLayer( layer ) )
324 continue;
325
326 // Skip vias annulus when not flashed on this layer
327 if( track->Type() == PCB_VIA_T && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
328 continue;
329
330 // Add object item to layer container
331 createTrackWithMargin( track, layerContainer, layer );
332 }
333 }
334
335 // Create VIAS and THTs objects and add it to holes containers
336 for( PCB_LAYER_ID layer : layer_ids )
337 {
338 // Check if the layer is already created
339 if( !m_layerHoleMap.contains( layer ) )
340 {
341 m_layerHoleMap[layer] = new BVH_CONTAINER_2D;
342 }
343
344 // ADD TRACKS
345 unsigned int nTracks = trackList.size();
346
347 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
348 {
349 const PCB_TRACK *track = trackList[trackIdx];
350
351 if( !track->IsOnLayer( layer ) )
352 continue;
353
354 // ADD VIAS and THT
355 if( track->Type() == PCB_VIA_T )
356 {
357 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
358 const VIATYPE viatype = via->GetViaType();
359 const double holediameter = via->GetDrillValue() * BiuTo3dUnits();
360 const double viasize = via->GetWidth( layer ) * BiuTo3dUnits();
361 const double plating = GetHolePlatingThickness() * BiuTo3dUnits();
362
363 // holes and layer copper extend half info cylinder wall to hide transition
364 const float thickness = static_cast<float>( plating / 2.0f );
365 const float hole_inner_radius = static_cast<float>( holediameter / 2.0f );
366 const float ring_radius = static_cast<float>( viasize / 2.0f );
367
368 const SFVEC2F via_center( via->GetStart().x * m_biuTo3Dunits,
369 -via->GetStart().y * m_biuTo3Dunits );
370
371 if( viatype != VIATYPE::THROUGH )
372 {
373 // Add hole objects
374 BVH_CONTAINER_2D *layerHoleContainer = nullptr;
375 layerHoleContainer = m_layerHoleMap[layer];
376
377 // Add a hole for this layer
378 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness,
379 *track ) );
380 }
381 else if( layer == layer_ids[0] ) // it only adds once the THT holes
382 {
383 // Add through hole object
384 m_TH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
385 m_viaTH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
386
387 if( cfg.clip_silk_on_via_annuli && ring_radius > 0.0 )
388 m_viaAnnuli.Add( new FILLED_CIRCLE_2D( via_center, ring_radius, *track ) );
389
390 if( hole_inner_radius > 0.0 )
391 m_TH_IDs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius, *track ) );
392 }
393
394 // Add counterbore/countersink cutouts for vias
395 const auto frontMode = via->GetFrontPostMachining().value_or( PAD_DRILL_POST_MACHINING_MODE::UNKNOWN );
396 const double frontRadius = via->GetFrontPostMachiningSize() * m_biuTo3Dunits / 2.0;
397
400 && frontRadius > hole_inner_radius )
401 {
402 if( layer == layer_ids[0] ) // only add once for front layer
403 {
405 m_frontCounterboreCutouts.Add( new FILLED_CIRCLE_2D( via_center, frontRadius, *track ) );
406 else if( frontMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
407 m_frontCountersinkCutouts.Add( new FILLED_CIRCLE_2D( via_center, frontRadius, *track ) );
408 }
409
410 BVH_CONTAINER_2D *layerHoleContainer = m_layerHoleMap[layer];
411 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, frontRadius + thickness, *track ) );
412 }
413
414 const auto backMode = via->GetBackPostMachining().value_or( PAD_DRILL_POST_MACHINING_MODE::UNKNOWN );
415 const double backRadius = via->GetBackPostMachiningSize() * m_biuTo3Dunits / 2.0;
416
419 && backRadius > hole_inner_radius )
420 {
421
422 if( layer == layer_ids.back() ) // only add once for back layer
423 {
425 m_backCounterboreCutouts.Add( new FILLED_CIRCLE_2D( via_center, backRadius, *track ) );
426 else if( backMode == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
427 m_backCountersinkCutouts.Add( new FILLED_CIRCLE_2D( via_center, backRadius, *track ) );
428 }
429
430 BVH_CONTAINER_2D *layerHoleContainer = m_layerHoleMap[layer];
431 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, backRadius + thickness, *track ) );
432 }
433
434 // Add backdrill cutouts for vias - affects specific layers only
435 float backdrillRadius = via->GetSecondaryDrillSize().value_or( 0 ) * m_biuTo3Dunits / 2.0f ;
436
437 // Only add if backdrill is larger than original hole
438 if( backdrillRadius > hole_inner_radius + thickness )
439 {
440 PCB_LAYER_ID secStart = via->GetSecondaryDrillStartLayer();
441 PCB_LAYER_ID secEnd = via->GetSecondaryDrillEndLayer();
442
443 bool validLyPair = secStart >= 0 && secEnd >= 0;
444
445 if( validLyPair && LAYER_RANGE( secStart, secEnd, m_copperLayersCount ).Contains( layer ) )
446 {
447 // Add to layer hole map for this layer
448 BVH_CONTAINER_2D* layerHoleContainer = m_layerHoleMap[layer];
449
450 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, backdrillRadius, *track ) );
451 }
452
453 if( validLyPair && layer == secStart )
454 m_backdrillCutouts.Add( new FILLED_CIRCLE_2D( via_center, backdrillRadius, *track ) );
455 }
456
457 // Add tertiary drill cutouts for vias - affects specific layers only
458 float tertiaryDrillRadius = via->GetTertiaryDrillSize().value_or( 0 ) * m_biuTo3Dunits / 2.0f ;
459
460 // Only add if tertiary drill is larger than original hole
461 if( tertiaryDrillRadius > hole_inner_radius + thickness )
462 {
463 PCB_LAYER_ID terStart = via->GetTertiaryDrillStartLayer();
464 PCB_LAYER_ID terEnd = via->GetTertiaryDrillEndLayer();
465
466 bool validLyPair = terStart >= 0 && terEnd >= 0;
467
468 if( validLyPair && LAYER_RANGE( terStart, terEnd, m_copperLayersCount ).Contains( layer ) )
469 {
470 // Add to layer hole map for this layer
471 BVH_CONTAINER_2D* layerHoleContainer = m_layerHoleMap[layer];
472
473 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center, tertiaryDrillRadius, *track ) );
474 }
475
476 if( validLyPair && layer == terStart )
477 m_tertiarydrillCutouts.Add( new FILLED_CIRCLE_2D( via_center, tertiaryDrillRadius, *track ) );
478 }
479 }
480
481 if( cfg.DifferentiatePlatedCopper() && layer == F_Cu )
482 {
484 ERROR_INSIDE );
485 }
486 else if( cfg.DifferentiatePlatedCopper() && layer == B_Cu )
487 {
489 ERROR_INSIDE );
490 }
491 }
492 }
493
494 // Create VIAS and THTs objects and add it to holes containers
495 for( PCB_LAYER_ID layer : layer_ids )
496 {
497 if( !m_layerHoleOdPolys.contains( layer ) )
498 {
500 }
501
502 if( !m_layerHoleIdPolys.contains( layer ) )
503 {
505 }
506
507 // ADD TRACKS
508 const unsigned int nTracks = trackList.size();
509
510 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
511 {
512 const PCB_TRACK *track = trackList[trackIdx];
513
514 if( !track->IsOnLayer( layer ) )
515 continue;
516
517 // ADD VIAS and THT
518 if( track->Type() == PCB_VIA_T )
519 {
520 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
521 const VIATYPE viatype = via->GetViaType();
522
523 // Add outer holes of VIAs
524 SHAPE_POLY_SET *layerOuterHolesPoly = nullptr;
525 SHAPE_POLY_SET *layerInnerHolesPoly = nullptr;
526
527 // found
528 wxASSERT( m_layerHoleOdPolys.contains( layer ) );
529 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
530
531 layerOuterHolesPoly = m_layerHoleOdPolys[layer];
532 layerInnerHolesPoly = m_layerHoleIdPolys[layer];
533
534 const int holediameter = via->GetDrillValue();
535 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
536
537 if( viatype != VIATYPE::THROUGH )
538 {
539 // Add PCB_VIA hole contours
540 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(), hole_outer_radius,
541 via->GetMaxError(), ERROR_INSIDE );
542
543 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(), holediameter / 2,
544 via->GetMaxError(), ERROR_INSIDE );
545 }
546 else if( layer == layer_ids[0] ) // it only adds once the THT holes
547 {
548 const int hole_outer_ring_radius = KiROUND( via->GetWidth( layer ) / 2.0 );
549
550 // Add through hole contours
551 TransformCircleToPolygon( m_TH_ODPolys, via->GetStart(), hole_outer_radius,
552 via->GetMaxError(), ERROR_INSIDE );
553
554 // Add same thing for vias only
555 TransformCircleToPolygon( m_viaTH_ODPolys, via->GetStart(), hole_outer_radius,
556 via->GetMaxError(), ERROR_INSIDE );
557
559 {
560 TransformCircleToPolygon( m_viaAnnuliPolys, via->GetStart(), hole_outer_ring_radius,
561 via->GetMaxError(), ERROR_INSIDE );
562 }
563 }
564
565 // Add counterbore/countersink polygons for vias
566 const auto frontMode = via->GetFrontPostMachining();
567
568 if( frontMode.has_value()
570 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
571 {
572 const int frontRadiusBIU = via->GetFrontPostMachiningSize() / 2;
573
574 if( frontRadiusBIU > holediameter / 2 )
575 {
576 int frontRadiusOuterBIU = frontRadiusBIU + GetHolePlatingThickness();
577
578 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
579 {
581 frontRadiusBIU, via->GetMaxError(),
582 ERROR_INSIDE );
583 }
584 else if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
585 {
587 frontRadiusBIU, via->GetMaxError(),
588 ERROR_INSIDE );
589 }
590
591 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(),
592 frontRadiusOuterBIU, via->GetMaxError(),
593 ERROR_INSIDE );
594 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(),
595 frontRadiusBIU, via->GetMaxError(),
596 ERROR_INSIDE );
597 }
598 }
599
600 const auto backMode = via->GetBackPostMachining();
601
602 if( backMode.has_value()
604 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
605 {
606 const int backRadiusBIU = via->GetBackPostMachiningSize() / 2;
607
608 if( backRadiusBIU > holediameter / 2 )
609 {
610 int backRadiusOuterBIU = backRadiusBIU + GetHolePlatingThickness();
611
612 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
613 {
615 backRadiusBIU, via->GetMaxError(),
616 ERROR_INSIDE );
617 }
618 else if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
619 {
621 backRadiusBIU, via->GetMaxError(),
622 ERROR_INSIDE );
623 }
624
625 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(),
626 backRadiusOuterBIU, via->GetMaxError(),
627 ERROR_INSIDE );
628 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(),
629 backRadiusBIU, via->GetMaxError(),
630 ERROR_INSIDE );
631 }
632 }
633
634 // Add backdrill polygons for vias - affects specific layers only
635 const auto secondaryDrillSize = via->GetSecondaryDrillSize();
636
637 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
638 {
639 const int backdrillRadiusBIU = secondaryDrillSize.value() / 2;
640 const int backdrillOuterRadiusBIU = backdrillRadiusBIU + GetHolePlatingThickness();
641 const int holeOuterRadiusBIU = hole_outer_radius;
642
643 // Only add if backdrill is larger than original hole outer diameter
644 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
645 {
646 PCB_LAYER_ID secStart = via->GetSecondaryDrillStartLayer();
647 PCB_LAYER_ID secEnd = via->GetSecondaryDrillEndLayer();
648 bool validLyPair = secStart >= 0 && secEnd >= 0;
649
650 // Iterate through layers affected by backdrill
651 if( validLyPair && LAYER_RANGE( secStart, secEnd, m_copperLayersCount ).Contains( layer ) )
652 {
653 TransformCircleToPolygon( *m_layerHoleOdPolys[layer], via->GetStart(),
654 backdrillOuterRadiusBIU, via->GetMaxError(),
655 ERROR_INSIDE );
656
657 TransformCircleToPolygon( *m_layerHoleIdPolys[layer], via->GetStart(),
658 backdrillRadiusBIU, via->GetMaxError(),
659 ERROR_INSIDE );
660
662 backdrillOuterRadiusBIU, via->GetMaxError(),
663 ERROR_INSIDE );
664 }
665 }
666 }
667
668 // Add backdrill polygons for vias - affects specific layers only
669 const auto tertiaryDrillSize = via->GetTertiaryDrillSize();
670
671 if( tertiaryDrillSize.has_value() && tertiaryDrillSize.value() > 0 )
672 {
673 const int backdrillRadiusBIU = tertiaryDrillSize.value() / 2;
674 const int backdrillOuterRadiusBIU = backdrillRadiusBIU + GetHolePlatingThickness();
675 const int holeOuterRadiusBIU = hole_outer_radius;
676
677 // Only add if backdrill is larger than original hole outer diameter
678 if( backdrillOuterRadiusBIU > holeOuterRadiusBIU )
679 {
680 PCB_LAYER_ID terStart = via->GetTertiaryDrillStartLayer();
681 PCB_LAYER_ID terEnd = via->GetTertiaryDrillEndLayer();
682 bool validLyPair = terStart >= 0 && terEnd >= 0;
683
684 if( validLyPair && LAYER_RANGE( terStart, terEnd, m_copperLayersCount ).Contains( layer ) )
685 {
686 PCB_LAYER_ID backdrillLayer = layer;
687
688 TransformCircleToPolygon( *m_layerHoleOdPolys[backdrillLayer], via->GetStart(),
689 backdrillOuterRadiusBIU, via->GetMaxError(),
690 ERROR_INSIDE );
691
692 TransformCircleToPolygon( *m_layerHoleIdPolys[backdrillLayer], via->GetStart(),
693 backdrillRadiusBIU, via->GetMaxError(),
694 ERROR_INSIDE );
695
697 backdrillOuterRadiusBIU, via->GetMaxError(),
698 ERROR_INSIDE );
699 }
700 }
701 }
702 }
703 }
704 }
705
706 // Creates vertical outline contours of the tracks and add it to the poly of the layer
708 {
709 for( PCB_LAYER_ID layer : layer_ids )
710 {
711 wxASSERT( m_layers_poly.contains( layer ) );
712
713 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
714
715 // ADD TRACKS
716 unsigned int nTracks = trackList.size();
717
718 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
719 {
720 const PCB_TRACK *track = trackList[trackIdx];
721
722 if( !track->IsOnLayer( layer ) )
723 continue;
724
725 // Skip vias annulus when not flashed on this layer
726 if( track->Type() == PCB_VIA_T && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
727 continue;
728
729 // Add the track/via contour
730 track->TransformShapeToPolygon( *layerPoly, layer, 0, track->GetMaxError(), ERROR_INSIDE );
731 }
732 }
733 }
734
735 // Add holes of footprints
736 for( FOOTPRINT* footprint : m_board->Footprints() )
737 {
738 for( PAD* pad : footprint->Pads() )
739 {
740 // Note: holes of NPTH are already built by GetBoardPolygonOutlines
741 if( !pad->HasHole() )
742 continue;
743
744 m_holeCount++;
745 double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
746 m_averageHoleDiameter += static_cast<float>( holeDiameter * m_biuTo3Dunits );
747
748 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
749 {
750 // Ensure the silk drawings are clipped to the NPTH hole, like other pad/via holes
751 // even if the clip to board body is not activated (remember NPTH holes are part of
752 // the board body)
754 continue;
755 }
756
757 // The hole in the body is inflated by copper thickness
758 int inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
759
760 createPadHoleShape( pad, &m_TH_ODs, inflate );
761
763 createPadHoleShape( pad, &m_viaAnnuli, inflate );
764
766
767 // Add counterbore/countersink cutouts for pads
768 const float holeDiameterUnits = static_cast<float>(
769 ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0 * m_biuTo3Dunits );
770 const float holeInnerRadius = holeDiameterUnits / 2.0f;
771 const SFVEC2F padCenter( pad->GetPosition().x * static_cast<float>( m_biuTo3Dunits ),
772 -pad->GetPosition().y * static_cast<float>( m_biuTo3Dunits ) );
773
774 const auto frontMode = pad->GetFrontPostMachining();
775
776 if( frontMode.has_value()
778 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
779 {
780 const float frontRadius = pad->GetFrontPostMachiningSize() * 0.5f
781 * static_cast<float>( m_biuTo3Dunits );
782
783 if( frontRadius > holeInnerRadius )
784 {
785 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
786 {
788 new FILLED_CIRCLE_2D( padCenter, frontRadius, *pad ) );
789 }
790 else if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
791 {
793 new FILLED_CIRCLE_2D( padCenter, frontRadius, *pad ) );
794 }
795 }
796 }
797
798 const auto backMode = pad->GetBackPostMachining();
799
800 if( backMode.has_value()
802 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
803 {
804 const float backRadius = pad->GetBackPostMachiningSize() * 0.5f
805 * static_cast<float>( m_biuTo3Dunits );
806
807 if( backRadius > holeInnerRadius )
808 {
809 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
810 {
812 new FILLED_CIRCLE_2D( padCenter, backRadius, *pad ) );
813 }
814 else if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
815 {
817 new FILLED_CIRCLE_2D( padCenter, backRadius, *pad ) );
818 }
819 }
820 }
821
822 // Add backdrill cutouts for pads - affects specific layers only
823 const VECTOR2I& secDrillSize = pad->GetSecondaryDrillSize();
824
825 if( secDrillSize.x > 0 || secDrillSize.y > 0 )
826 {
827 const float backdrillRadius = ( secDrillSize.x + secDrillSize.y ) * 0.25f
828 * static_cast<float>( m_biuTo3Dunits );
829
830 // The hole outer diameter with plating
831 const float holeOuterRadius = holeInnerRadius
832 + static_cast<float>( GetHolePlatingThickness()
833 * m_biuTo3Dunits );
834
835 // Only add if backdrill is larger than original hole outer diameter
836 if( backdrillRadius > holeOuterRadius )
837 {
838 PCB_LAYER_ID secStart = pad->GetSecondaryDrillStartLayer();
839 PCB_LAYER_ID secEnd = pad->GetSecondaryDrillEndLayer();
840 bool validLyPair = secStart >= 0 && secEnd >= 0;
841
842 // Iterate through layers affected by backdrill
843 if( validLyPair )
844 {
845 for( PCB_LAYER_ID backdrillLayer : LAYER_RANGE( secStart, secEnd,
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(
862 new FILLED_CIRCLE_2D( padCenter, backdrillRadius, *pad ) );
863 }
864 }
865 }
866 }
867 }
868 }
869
870 if( m_holeCount )
872
873 // Add contours of the pad holes (pads can be Circle or Segment holes)
874 for( FOOTPRINT* footprint : m_board->Footprints() )
875 {
876 for( PAD* pad : footprint->Pads() )
877 {
878 if( !pad->HasHole() )
879 continue;
880
881 // The hole in the body is inflated by copper thickness.
882 const int inflate = GetHolePlatingThickness();
883
884 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
885 {
887 pad->TransformHoleToPolygon( m_viaAnnuliPolys, inflate, pad->GetMaxError(), ERROR_INSIDE );
888
889 pad->TransformHoleToPolygon( m_TH_ODPolys, inflate, pad->GetMaxError(), ERROR_INSIDE );
890 }
891 else
892 {
893 // If not plated, no copper.
895 pad->TransformHoleToPolygon( m_viaAnnuliPolys, 0, pad->GetMaxError(), ERROR_INSIDE );
896
897 pad->TransformHoleToPolygon( m_NPTH_ODPolys, 0, pad->GetMaxError(), ERROR_INSIDE );
898 }
899
900
901 // Add counterbore/countersink polygons for pads
902 const double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
903 const int holeRadius = KiROUND( holeDiameter / 2.0 );
904
905 const auto frontMode = pad->GetFrontPostMachining();
906
907 if( frontMode.has_value()
909 && frontMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
910 {
911 const int frontRadiusBIU = pad->GetFrontPostMachiningSize() / 2;
912
913 if( frontRadiusBIU > holeRadius )
914 {
915 if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
916 {
918 frontRadiusBIU, pad->GetMaxError(),
919 ERROR_INSIDE );
920 }
921 else if( frontMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
922 {
924 frontRadiusBIU, pad->GetMaxError(),
925 ERROR_INSIDE );
926 }
927 }
928 }
929
930 const auto backMode = pad->GetBackPostMachining();
931
932 if( backMode.has_value()
934 && backMode.value() != PAD_DRILL_POST_MACHINING_MODE::UNKNOWN )
935 {
936 const int backRadiusBIU = pad->GetBackPostMachiningSize() / 2;
937
938 if( backRadiusBIU > holeRadius )
939 {
940 if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE )
941 {
943 backRadiusBIU, pad->GetMaxError(),
944 ERROR_INSIDE );
945 }
946 else if( backMode.value() == PAD_DRILL_POST_MACHINING_MODE::COUNTERSINK )
947 {
949 backRadiusBIU, pad->GetMaxError(),
950 ERROR_INSIDE );
951 }
952 }
953 }
954
955 // Add backdrill polygons for pads - affects specific layers only
956 const VECTOR2I& secDrillSize = pad->GetSecondaryDrillSize();
957
958 if( secDrillSize.x > 0 || secDrillSize.y > 0 )
959 {
960 const int backdrillRadiusBIU = ( secDrillSize.x + secDrillSize.y ) / 4;
961 const int holeOuterRadiusBIU = holeRadius + inflate;
962
963 // Only add if backdrill is larger than original hole outer diameter
964 if( backdrillRadiusBIU > holeOuterRadiusBIU )
965 {
966 PCB_LAYER_ID secStart = pad->GetSecondaryDrillStartLayer();
967 PCB_LAYER_ID secEnd = pad->GetSecondaryDrillEndLayer();
968 bool validLyPair = secStart >= 0 && secEnd >= 0;
969
970 if( validLyPair )
971 {
973 backdrillRadiusBIU, pad->GetMaxError(),
974 ERROR_INSIDE );
975
976 // Iterate through layers affected by backdrill
977 for( PCB_LAYER_ID backdrillLayer : LAYER_RANGE( secStart, secEnd,
979 {
980 // Add polygon to per-layer hole polys
981 SHAPE_POLY_SET* layerHolePoly = nullptr;
982
983 if( !m_layerHoleOdPolys.contains( backdrillLayer ) )
984 {
985 layerHolePoly = new SHAPE_POLY_SET;
986 m_layerHoleOdPolys[backdrillLayer] = layerHolePoly;
987 }
988 else
989 {
990 layerHolePoly = m_layerHoleOdPolys[backdrillLayer];
991 }
992
993 TransformCircleToPolygon( *layerHolePoly, pad->GetPosition(),
994 backdrillRadiusBIU, pad->GetMaxError(),
995 ERROR_INSIDE );
996 }
997 }
998 }
999 }
1000 }
1001 }
1002
1003 // Add footprints copper items (pads, shapes and text) to containers
1004 for( PCB_LAYER_ID layer : layer_ids )
1005 {
1006 wxASSERT( m_layerMap.contains( layer ) );
1007
1008 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
1009
1010 for( FOOTPRINT* fp : m_board->Footprints() )
1011 {
1012 addPads( fp, layerContainer, layer );
1013 addFootprintShapes( fp, layerContainer, layer, visibilityFlags );
1014
1015 // Add copper item to the plated copper polygon list if required
1016 if( cfg.DifferentiatePlatedCopper() && IsExternalCopperLayer( layer ) )
1017 {
1019
1020 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), ERROR_INSIDE );
1021 transformFPTextToPolySet( fp, layer, visibilityFlags, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1022 transformFPShapesToPolySet( fp, layer, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1023 }
1024
1025 // Add copper item to poly contours (vertical outlines) if required
1027 {
1028 wxASSERT( m_layers_poly.contains( layer ) );
1029
1030 SHAPE_POLY_SET* layerPoly = m_layers_poly[layer];
1031
1032 fp->TransformPadsToPolySet( *layerPoly, layer, 0, fp->GetMaxError(), ERROR_INSIDE );
1033 transformFPTextToPolySet( fp, layer, visibilityFlags, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1034 transformFPShapesToPolySet( fp, layer, *layerPoly, fp->GetMaxError(), ERROR_INSIDE );
1035 }
1036 }
1037 }
1038
1039 // Add graphic item on copper layers to object containers
1040 for( PCB_LAYER_ID layer : layer_ids )
1041 {
1042 wxASSERT( m_layerMap.contains( layer ) );
1043
1044 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
1045
1046 // Add graphic items on copper layers (texts and other graphics)
1047 for( BOARD_ITEM* item : m_board->Drawings() )
1048 {
1049 if( !item->IsOnLayer( layer ) )
1050 continue;
1051
1052 switch( item->Type() )
1053 {
1054 case PCB_SHAPE_T:
1055 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
1056 break;
1057
1058 case PCB_TEXT_T:
1059 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
1060 break;
1061
1062 case PCB_TEXTBOX_T:
1063 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
1064 break;
1065
1066 case PCB_TABLE_T:
1067 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
1068 break;
1069
1070 case PCB_BARCODE_T:
1071 addBarCode( static_cast<PCB_BARCODE*>( item ), layerContainer, item );
1072 break;
1073
1074 case PCB_DIM_ALIGNED_T:
1075 case PCB_DIM_CENTER_T:
1076 case PCB_DIM_RADIAL_T:
1078 case PCB_DIM_LEADER_T:
1079 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
1080 break;
1081
1082 case PCB_REFERENCE_IMAGE_T: // ignore
1083 break;
1084
1085 default:
1086 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), item->Type() );
1087 break;
1088 }
1089
1090 // Add copper item to the plated copper polygon list if required
1091 if( cfg.DifferentiatePlatedCopper() && IsExternalCopperLayer( layer ) )
1092 {
1094
1095 // Note: for TEXT and TEXTBOX, TransformShapeToPolygon returns the bounding
1096 // box shape, not the exact text shape. So it is not used for these items
1097 if( item->Type() == PCB_TEXTBOX_T )
1098 {
1099 PCB_TEXTBOX* text_box = static_cast<PCB_TEXTBOX*>( item );
1100 text_box->TransformTextToPolySet( *copperPolys, 0, text_box->GetMaxError(), ERROR_INSIDE );
1101
1102 // Add box outlines
1103 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, text_box->GetMaxError(),
1104 ERROR_INSIDE );
1105 }
1106 else if( item->Type() == PCB_TEXT_T )
1107 {
1108 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1109 text->TransformTextToPolySet( *copperPolys, 0, text->GetMaxError(), ERROR_INSIDE );
1110 }
1111 else if( item->Type() != PCB_REFERENCE_IMAGE_T )
1112 {
1113 item->TransformShapeToPolySet( *copperPolys, layer, 0, item->GetMaxError(), ERROR_INSIDE );
1114 }
1115 }
1116
1117 // Add copper item to poly contours (vertical outlines) if required
1119 {
1120 wxASSERT( m_layers_poly.contains( layer ) );
1121
1122 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
1123
1124 switch( item->Type() )
1125 {
1126 case PCB_SHAPE_T:
1127 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), ERROR_INSIDE );
1128 break;
1129
1130 case PCB_TEXT_T:
1131 {
1132 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1133
1134 text->TransformTextToPolySet( *layerPoly, 0, text->GetMaxError(), ERROR_INSIDE );
1135 break;
1136 }
1137
1138 case PCB_TEXTBOX_T:
1139 {
1140 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
1141
1142 if( textbox->IsBorderEnabled() )
1143 {
1144 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, textbox->GetMaxError(),
1145 ERROR_INSIDE );
1146 }
1147
1148 textbox->TransformTextToPolySet( *layerPoly, 0, textbox->GetMaxError(), ERROR_INSIDE );
1149 break;
1150 }
1151
1152 case PCB_TABLE_T:
1153 {
1154 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
1155
1156 for( PCB_TABLECELL* cell : table->GetCells() )
1157 cell->TransformTextToPolySet( *layerPoly, 0, cell->GetMaxError(), ERROR_INSIDE );
1158
1159 table->DrawBorders(
1160 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
1161 const STROKE_PARAMS& stroke )
1162 {
1163 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
1164 seg.TransformToPolygon( *layerPoly, table->GetMaxError(), ERROR_INSIDE );
1165 } );
1166 break;
1167 }
1168
1169 case PCB_BARCODE_T:
1170 {
1171 PCB_BARCODE* bar_code = static_cast<PCB_BARCODE*>( item );
1172
1173 bar_code->TransformShapeToPolySet( *layerPoly, layer, 0, 0, ERROR_INSIDE );
1174 break;
1175 }
1176
1177 case PCB_DIM_ALIGNED_T:
1178 case PCB_DIM_CENTER_T:
1179 case PCB_DIM_RADIAL_T:
1181 case PCB_DIM_LEADER_T:
1182 {
1183 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
1184
1185 dimension->TransformTextToPolySet( *layerPoly, 0, dimension->GetMaxError(), ERROR_INSIDE );
1186
1187 for( const std::shared_ptr<SHAPE>& shape : dimension->GetShapes() )
1188 shape->TransformToPolygon( *layerPoly, dimension->GetMaxError(), ERROR_INSIDE );
1189
1190 break;
1191 }
1192
1193 case PCB_REFERENCE_IMAGE_T: // ignore
1194 break;
1195
1196 default:
1197 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ), item->Type() );
1198 break;
1199 }
1200 }
1201 }
1202 }
1203
1204 if( cfg.show_zones )
1205 {
1206 if( aStatusReporter )
1207 aStatusReporter->Report( _( "Create zones" ) );
1208
1209 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
1210 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
1211
1212 for( ZONE* zone : m_board->Zones() )
1213 {
1214 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
1215 {
1216 zones.emplace_back( std::make_pair( zone, layer ) );
1217 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
1218
1219 if( cfg.DifferentiatePlatedCopper() && IsExternalCopperLayer( layer ) )
1220 {
1222
1223 zone->TransformShapeToPolygon( *copperPolys, layer, 0, zone->GetMaxError(), ERROR_INSIDE );
1224 }
1225 }
1226 }
1227
1228 // Add zones objects
1229 std::atomic<size_t> nextZone( 0 );
1230 std::atomic<size_t> threadsFinished( 0 );
1231
1232 size_t parallelThreadCount = std::min<size_t>( zones.size(),
1233 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
1234
1235 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1236 {
1237 std::thread t = std::thread( [&]()
1238 {
1239 for( size_t areaId = nextZone.fetch_add( 1 );
1240 areaId < zones.size();
1241 areaId = nextZone.fetch_add( 1 ) )
1242 {
1243 ZONE* zone = zones[areaId].first;
1244
1245 if( zone == nullptr )
1246 break;
1247
1248 PCB_LAYER_ID layer = zones[areaId].second;
1249
1250 if( m_layerMap.contains( layer ) )
1251 addSolidAreasShapes( zone, m_layerMap[layer], layer );
1252
1254 && m_layers_poly.contains( layer ) )
1255 {
1256 auto mut_it = layer_lock.find( layer );
1257
1258 if( mut_it != layer_lock.end() )
1259 {
1260 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
1261 zone->TransformSolidAreasShapesToPolygon( layer, *m_layers_poly[layer] );
1262 }
1263 }
1264 }
1265
1266 threadsFinished++;
1267 } );
1268
1269 t.detach();
1270 }
1271
1272 while( threadsFinished < parallelThreadCount )
1273 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1274 }
1275 // End Build Copper layers
1276
1277 // This will make a union of all added contours
1278 m_TH_ODPolys.Simplify();
1279 m_NPTH_ODPolys.Simplify();
1280 m_viaTH_ODPolys.Simplify();
1281 m_viaAnnuliPolys.Simplify();
1282
1283 m_frontCounterborePolys.Simplify();
1284 m_backCounterborePolys.Simplify();
1285 m_frontCountersinkPolys.Simplify();
1286 m_backCountersinkPolys.Simplify();
1287
1288 // Remove counterbore/countersink/backdrill cutouts from via annuli (both front and back)
1289 // The via annuli are used for silkscreen clipping and shouldn't include areas removed
1290 // by counterbore, countersink, or backdrill operations
1291 if( m_viaAnnuliPolys.OutlineCount() > 0 )
1292 {
1293 if( m_frontCounterborePolys.OutlineCount() > 0 )
1294 m_viaAnnuliPolys.BooleanSubtract( m_frontCounterborePolys );
1295
1296 if( m_backCounterborePolys.OutlineCount() > 0 )
1297 m_viaAnnuliPolys.BooleanSubtract( m_backCounterborePolys );
1298
1299 if( m_frontCountersinkPolys.OutlineCount() > 0 )
1300 m_viaAnnuliPolys.BooleanSubtract( m_frontCountersinkPolys );
1301
1302 if( m_backCountersinkPolys.OutlineCount() > 0 )
1303 m_viaAnnuliPolys.BooleanSubtract( m_backCountersinkPolys );
1304
1305 if( m_BackdrillPolys.OutlineCount() > 0 )
1306 m_viaAnnuliPolys.BooleanSubtract( m_BackdrillPolys );
1307
1308 if( m_TertiarydrillPolys.OutlineCount() > 0 )
1309 m_viaAnnuliPolys.BooleanSubtract( m_TertiarydrillPolys );
1310 }
1311
1312 // Build Tech layers
1313 // Based on:
1314 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
1315 if( aStatusReporter )
1316 aStatusReporter->Report( _( "Build Tech layers" ) );
1317
1318 // draw graphic items, on technical layers
1319
1320 LSEQ techLayerList = LSET::AllNonCuMask().Seq( {
1321 B_Adhes,
1322 F_Adhes,
1323 B_Paste,
1324 F_Paste,
1325 B_SilkS,
1326 F_SilkS,
1327 B_Mask,
1328 F_Mask,
1329
1330 // Aux Layers
1331 Dwgs_User,
1332 Cmts_User,
1333 Eco1_User,
1334 Eco2_User,
1335 User_1,
1336 User_2,
1337 User_3,
1338 User_4,
1339 User_5,
1340 User_6,
1341 User_7,
1342 User_8,
1343 User_9,
1344 User_10,
1345 User_11,
1346 User_12,
1347 User_13,
1348 User_14,
1349 User_15,
1350 User_16,
1351 User_17,
1352 User_18,
1353 User_19,
1354 User_20,
1355 User_21,
1356 User_22,
1357 User_23,
1358 User_24,
1359 User_25,
1360 User_26,
1361 User_27,
1362 User_28,
1363 User_29,
1364 User_30,
1365 User_31,
1366 User_32,
1367 User_33,
1368 User_34,
1369 User_35,
1370 User_36,
1371 User_37,
1372 User_38,
1373 User_39,
1374 User_40,
1375 User_41,
1376 User_42,
1377 User_43,
1378 User_44,
1379 User_45,
1380 } );
1381
1382 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
1383
1385 {
1386 enabledFlags.set( LAYER_3D_SOLDERMASK_TOP );
1387 enabledFlags.set( LAYER_3D_SOLDERMASK_BOTTOM );
1388 }
1389
1390 for( PCB_LAYER_ID layer : techLayerList )
1391 {
1392 if( aStatusReporter )
1393 aStatusReporter->Report( wxString::Format( _( "Build Tech layer %d" ), (int) layer ) );
1394
1395 if( !Is3dLayerEnabled( layer, enabledFlags ) )
1396 continue;
1397
1398 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
1399 m_layerMap[layer] = layerContainer;
1400
1401 SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
1402 m_layers_poly[layer] = layerPoly;
1403
1404 if( Is3dLayerEnabled( layer, visibilityFlags ) )
1405 {
1406 // Add drawing objects
1407 for( BOARD_ITEM* item : m_board->Drawings() )
1408 {
1409 if( !item->IsOnLayer( layer ) )
1410 continue;
1411
1412 switch( item->Type() )
1413 {
1414 case PCB_SHAPE_T:
1415 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
1416 break;
1417
1418 case PCB_TEXT_T:
1419 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
1420 break;
1421
1422 case PCB_TEXTBOX_T:
1423 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
1424 break;
1425
1426 case PCB_TABLE_T:
1427 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
1428 break;
1429
1430 case PCB_BARCODE_T:
1431 addBarCode( static_cast<PCB_BARCODE*>( item ), layerContainer, item );
1432 break;
1433
1434 case PCB_DIM_ALIGNED_T:
1435 case PCB_DIM_CENTER_T:
1436 case PCB_DIM_RADIAL_T:
1438 case PCB_DIM_LEADER_T:
1439 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
1440 break;
1441
1442 default:
1443 break;
1444 }
1445 }
1446
1447 // Add track, via and arc tech layers
1448 if( IsSolderMaskLayer( layer ) )
1449 {
1450 for( PCB_TRACK* track : m_board->Tracks() )
1451 {
1452 if( !track->IsOnLayer( layer ) )
1453 continue;
1454
1455 // Only vias on a external copper layer can have a solder mask
1456 PCB_LAYER_ID copper_layer = ( layer == F_Mask ) ? F_Cu : B_Cu;
1457
1458 if( track->Type() == PCB_VIA_T )
1459 {
1460 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1461
1462 if( !via->FlashLayer( copper_layer ) )
1463 continue;
1464 }
1465
1466 int maskExpansion = track->GetSolderMaskExpansion();
1467 createTrackWithMargin( track, layerContainer, layer, maskExpansion );
1468 }
1469 }
1470
1471 // Add footprints tech layers - objects. Paste, mask, silk and fab belong to the
1472 // board fabrication outputs and render for every footprint, matching the gerber
1473 // plotters. DNP affects only the 3D model, handled by IsFootprintShown().
1474 for( FOOTPRINT* footprint : m_board->Footprints() )
1475 {
1476 if( layer == F_SilkS || layer == B_SilkS )
1477 {
1478 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
1479
1480 for( PAD* pad : footprint->Pads() )
1481 {
1482 if( !pad->IsOnLayer( layer ) )
1483 continue;
1484
1485 buildPadOutlineAsSegments( pad, layer, layerContainer, linewidth );
1486 }
1487 }
1488 else
1489 {
1490 addPads( footprint, layerContainer, layer );
1491 }
1492
1493 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
1494 }
1495
1496 // Draw non copper zones
1497 if( cfg.show_zones )
1498 {
1499 for( ZONE* zone : m_board->Zones() )
1500 {
1501 if( zone->IsOnLayer( layer ) )
1502 addSolidAreasShapes( zone, layerContainer, layer );
1503 }
1504 }
1505 }
1506
1507 // Add item contours. We need these if we're building vertical walls or if this is a
1508 // mask layer and we're differentiating copper from plated copper.
1510 || ( cfg.DifferentiatePlatedCopper() && ( layer == F_Mask || layer == B_Mask ) ) )
1511 {
1512 // DRAWINGS
1513 for( BOARD_ITEM* item : m_board->Drawings() )
1514 {
1515 if( !item->IsOnLayer( layer ) )
1516 continue;
1517
1518 switch( item->Type() )
1519 {
1520 case PCB_SHAPE_T:
1521 item->TransformShapeToPolySet( *layerPoly, layer, 0, item->GetMaxError(), ERROR_INSIDE );
1522 break;
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:81
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:479
int GetMaxError() const
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
void Add(OBJECT_2D *aObject)
static DELETED_BOARD_ITEM * GetInstance()
Definition board_item.h:543
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
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:68
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:769
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:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:100
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:1894
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:746
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:558
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:557
@ 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:686
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
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ 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
std::vector< std::vector< std::string > > table
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:256
@ 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_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition typeinfo.h:93
@ 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