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