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