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