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