KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <mrluzeiro@ua.pt>
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"
27#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.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
41#ifdef PRINT_STATISTICS_3D_VIEWER
42#include <core/profile.h>
43#endif
44
45/*
46 * This is used to draw pad outlines on silk layers.
47 */
48void buildPadOutlineAsPolygon( const PAD* aPad, PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aBuffer,
49 int aWidth, int aMaxError, ERROR_LOC aErrorLoc )
50{
51 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
52 {
53 TransformRingToPolygon( aBuffer, aPad->ShapePos( aLayer ), aPad->GetSize( aLayer ).x / 2,
54 aWidth, aMaxError, aErrorLoc );
55 }
56 else
57 {
58 // For other shapes, add outlines as thick segments in polygon buffer
59 const SHAPE_LINE_CHAIN& path = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE )->COutline( 0 );
60
61 for( int ii = 0; ii < path.PointCount(); ++ii )
62 {
63 const VECTOR2I& a = path.CPoint( ii );
64 const VECTOR2I& b = path.CPoint( ii + 1 );
65
66 TransformOvalToPolygon( aBuffer, a, b, aWidth, aMaxError, aErrorLoc );
67 }
68 }
69}
70
71
72void transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
73 SHAPE_POLY_SET& aBuffer, int aMaxError, ERROR_LOC aErrorLoc )
74{
75 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
76 {
77 if( item->Type() == PCB_SHAPE_T || BaseType( item->Type() ) == PCB_DIMENSION_T )
78 {
79 if( item->GetLayer() == aLayer )
80 item->TransformShapeToPolySet( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
81 }
82 }
83}
84
85
86void transformFPTextToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
87 const std::bitset<LAYER_3D_END>& aFlags, SHAPE_POLY_SET& aBuffer,
88 int aMaxError, ERROR_LOC aErrorLoc )
89{
90 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
91 {
92 if( item->GetLayer() != aLayer )
93 continue;
94
95 if( item->Type() == PCB_TEXT_T )
96 {
97 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
98
99 if( !aFlags.test( LAYER_FP_TEXT ) )
100 continue;
101
102 if( text->GetText() == wxT( "${REFERENCE}" ) && !aFlags.test( LAYER_FP_REFERENCES ) )
103 continue;
104
105 if( text->GetText() == wxT( "${VALUE}" ) && !aFlags.test( LAYER_FP_VALUES ) )
106 continue;
107
108 if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer )
109 text->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
110 }
111
112 if( item->Type() == PCB_TEXTBOX_T )
113 {
114 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
115
116 if( aLayer != UNDEFINED_LAYER && textbox->GetLayer() == aLayer )
117 {
118 // border
119 if( textbox->IsBorderEnabled() )
120 textbox->PCB_SHAPE::TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
121
122 // text
123 textbox->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
124 }
125 }
126 }
127
128 for( const PCB_FIELD* field : aFootprint->GetFields() )
129 {
130 if( !aFlags.test( LAYER_FP_TEXT ) )
131 continue;
132
133 if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) )
134 continue;
135
136 if( field->IsValue() && !aFlags.test( LAYER_FP_VALUES ) )
137 continue;
138
139 if( field->GetLayer() == aLayer && field->IsVisible() )
140 field->TransformTextToPolySet( aBuffer, 0, aMaxError, aErrorLoc );
141 }
142}
143
144
146{
147#define DELETE_AND_FREE( ptr ) \
148 { \
149 delete ptr; \
150 ptr = nullptr; \
151 } \
152
153#define DELETE_AND_FREE_MAP( map ) \
154 { \
155 for( auto& [ layer, poly ] : map ) \
156 delete poly; \
157 \
158 map.clear(); \
159 }
160
162
165
168
173
176
181
182 m_TH_ODs.Clear();
183 m_TH_IDs.Clear();
186}
187
188
189void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
190{
192
193 // Build Copper layers
194 // Based on:
195 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
196
197#ifdef PRINT_STATISTICS_3D_VIEWER
198 int64_t stats_startCopperLayersTime = GetRunningMicroSecs();
199
200 int64_t start_Time = stats_startCopperLayersTime;
201#endif
202
204
205 std::bitset<LAYER_3D_END> visibilityFlags = GetVisibleLayers();
206
207 m_trackCount = 0;
209 m_viaCount = 0;
211 m_holeCount = 0;
213
214 if( !m_board )
215 return;
216
217 // Prepare track list, convert in a vector. Calc statistic for the holes
218 std::vector<const PCB_TRACK*> trackList;
219 trackList.clear();
220 trackList.reserve( m_board->Tracks().size() );
221
222 int maxError = m_board->GetDesignSettings().m_MaxError;
223
224 for( PCB_TRACK* track : m_board->Tracks() )
225 {
226 // Skip tracks (not vias theyt are on more than one layer ) on disabled layers
227 if( track->Type() != PCB_VIA_T
228 && !Is3dLayerEnabled( track->GetLayer(), visibilityFlags ) )
229 {
230 continue;
231 }
232
233 // Note: a PCB_TRACK holds normal segment tracks and also vias circles (that have also
234 // drill values)
235 trackList.push_back( track );
236
237 if( track->Type() == PCB_VIA_T )
238 {
239 const PCB_VIA *via = static_cast< const PCB_VIA*>( track );
240 m_viaCount++;
241 m_averageViaHoleDiameter += static_cast<float>( via->GetDrillValue() * m_biuTo3Dunits );
242 }
243 else
244 {
245 m_trackCount++;
246 m_averageTrackWidth += static_cast<float>( track->GetWidth() * m_biuTo3Dunits );
247 }
248 }
249
250 if( m_trackCount )
252
253 if( m_viaCount )
255
256 // Prepare copper layers index and containers
257 std::vector<PCB_LAYER_ID> layer_ids;
258 layer_ids.clear();
259 layer_ids.reserve( m_copperLayersCount );
260
262 {
263 if( !Is3dLayerEnabled( layer, visibilityFlags ) ) // Skip non enabled layers
264 continue;
265
266 layer_ids.push_back( layer );
267
268 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
269 m_layerMap[layer] = layerContainer;
270
271 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
272 {
273 SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
274 m_layers_poly[layer] = layerPoly;
275 }
276 }
277
278 if( cfg.DifferentiatePlatedCopper() )
279 {
282
285 }
286
287 if( cfg.show_off_board_silk )
288 {
291 }
292
293 if( aStatusReporter )
294 aStatusReporter->Report( _( "Create tracks and vias" ) );
295
296 // Create tracks as objects and add it to container
297 for( PCB_LAYER_ID layer : layer_ids )
298 {
299 wxASSERT( m_layerMap.contains( layer ) );
300
301 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
302
303 for( const PCB_TRACK* track : trackList )
304 {
305 // NOTE: Vias can be on multiple layers
306 if( !track->IsOnLayer( layer ) )
307 continue;
308
309 // Skip vias annulus when not flashed on this layer
310 if( track->Type() == PCB_VIA_T
311 && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
312 {
313 continue;
314 }
315
316 // Add object item to layer container
317 createTrackWithMargin( track, layerContainer, layer );
318 }
319 }
320
321 // Create VIAS and THTs objects and add it to holes containers
322 for( PCB_LAYER_ID layer : layer_ids )
323 {
324 // ADD TRACKS
325 unsigned int nTracks = trackList.size();
326
327 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
328 {
329 const PCB_TRACK *track = trackList[trackIdx];
330
331 if( !track->IsOnLayer( layer ) )
332 continue;
333
334 // ADD VIAS and THT
335 if( track->Type() == PCB_VIA_T )
336 {
337 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
338 const VIATYPE viatype = via->GetViaType();
339 const double holediameter = via->GetDrillValue() * BiuTo3dUnits();
340 const double viasize = via->GetWidth( layer ) * BiuTo3dUnits();
341 const double plating = GetHolePlatingThickness() * BiuTo3dUnits();
342
343 // holes and layer copper extend half info cylinder wall to hide transition
344 const float thickness = static_cast<float>( plating / 2.0f );
345 const float hole_inner_radius = static_cast<float>( holediameter / 2.0f );
346 const float ring_radius = static_cast<float>( viasize / 2.0f );
347
348 const SFVEC2F via_center( via->GetStart().x * m_biuTo3Dunits,
349 -via->GetStart().y * m_biuTo3Dunits );
350
351 if( viatype != VIATYPE::THROUGH )
352 {
353 // Add hole objects
354 BVH_CONTAINER_2D *layerHoleContainer = nullptr;
355
356 // Check if the layer is already created
357 if( !m_layerHoleMap.contains( layer ) )
358 {
359 // not found, create a new container
360 layerHoleContainer = new BVH_CONTAINER_2D;
361 m_layerHoleMap[layer] = layerHoleContainer;
362 }
363 else
364 {
365 // found
366 layerHoleContainer = m_layerHoleMap[layer];
367 }
368
369 // Add a hole for this layer
370 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center,
371 hole_inner_radius + thickness,
372 *track ) );
373 }
374 else if( layer == layer_ids[0] ) // it only adds once the THT holes
375 {
376 // Add through hole object
377 m_TH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
378 m_viaTH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness, *track ) );
379
380 if( cfg.clip_silk_on_via_annuli && ring_radius > 0.0 )
381 m_viaAnnuli.Add( new FILLED_CIRCLE_2D( via_center, ring_radius, *track ) );
382
383 if( hole_inner_radius > 0.0 )
384 m_TH_IDs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius, *track ) );
385 }
386 }
387
388 if( cfg.DifferentiatePlatedCopper() && layer == F_Cu )
390 else if( cfg.DifferentiatePlatedCopper() && layer == B_Cu )
392 }
393 }
394
395 // Create VIAS and THTs objects and add it to holes containers
396 for( PCB_LAYER_ID layer : layer_ids )
397 {
398 // ADD TRACKS
399 const unsigned int nTracks = trackList.size();
400
401 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
402 {
403 const PCB_TRACK *track = trackList[trackIdx];
404
405 if( !track->IsOnLayer( layer ) )
406 continue;
407
408 // ADD VIAS and THT
409 if( track->Type() == PCB_VIA_T )
410 {
411 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
412 const VIATYPE viatype = via->GetViaType();
413
414 if( viatype != VIATYPE::THROUGH )
415 {
416 // Add PCB_VIA hole contours
417
418 // Add outer holes of VIAs
419 SHAPE_POLY_SET *layerOuterHolesPoly = nullptr;
420 SHAPE_POLY_SET *layerInnerHolesPoly = nullptr;
421
422 // Check if the layer is already created
423 if( !m_layerHoleOdPolys.contains( layer ) )
424 {
425 // not found, create a new container
426 layerOuterHolesPoly = new SHAPE_POLY_SET;
427 m_layerHoleOdPolys[layer] = layerOuterHolesPoly;
428
429 wxASSERT( !m_layerHoleIdPolys.contains( layer ) );
430
431 layerInnerHolesPoly = new SHAPE_POLY_SET;
432 m_layerHoleIdPolys[layer] = layerInnerHolesPoly;
433 }
434 else
435 {
436 // found
437 layerOuterHolesPoly = m_layerHoleOdPolys[layer];
438
439 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
440
441 layerInnerHolesPoly = m_layerHoleIdPolys[layer];
442 }
443
444 const int holediameter = via->GetDrillValue();
445 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
446
447 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(), hole_outer_radius,
448 maxError, ERROR_INSIDE );
449
450 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(), holediameter / 2,
451 maxError, ERROR_INSIDE );
452 }
453 else if( layer == layer_ids[0] ) // it only adds once the THT holes
454 {
455 const int holediameter = via->GetDrillValue();
456 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
457 const int hole_outer_ring_radius = KiROUND( via->GetWidth( layer ) / 2.0 );
458
459 // Add through hole contours
460 TransformCircleToPolygon( m_TH_ODPolys, via->GetStart(), hole_outer_radius,
461 maxError, ERROR_INSIDE );
462
463 // Add same thing for vias only
464 TransformCircleToPolygon( m_viaTH_ODPolys, via->GetStart(), hole_outer_radius,
465 maxError, ERROR_INSIDE );
466
468 {
469 TransformCircleToPolygon( m_viaAnnuliPolys, via->GetStart(), hole_outer_ring_radius,
470 maxError, ERROR_INSIDE );
471 }
472 }
473 }
474 }
475 }
476
477 // Creates vertical outline contours of the tracks and add it to the poly of the layer
478 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
479 {
480 for( PCB_LAYER_ID layer : layer_ids )
481 {
482 wxASSERT( m_layers_poly.contains( layer ) );
483
484 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
485
486 // ADD TRACKS
487 unsigned int nTracks = trackList.size();
488
489 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
490 {
491 const PCB_TRACK *track = trackList[trackIdx];
492
493 if( !track->IsOnLayer( layer ) )
494 continue;
495
496 // Skip vias annulus when not flashed on this layer
497 if( track->Type() == PCB_VIA_T
498 && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
499 {
500 continue;
501 }
502
503 // Add the track/via contour
504 track->TransformShapeToPolygon( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
505 }
506 }
507 }
508
509 // Add holes of footprints
510 for( FOOTPRINT* footprint : m_board->Footprints() )
511 {
512 for( PAD* pad : footprint->Pads() )
513 {
514 const VECTOR2I padHole = pad->GetDrillSize();
515
516 if( !padHole.x ) // Not drilled pad like SMD pad
517 continue;
518
519 // The hole in the body is inflated by copper thickness, if not plated, no copper
520 int inflate = 0;
521
522 if( pad->GetAttribute () != PAD_ATTRIB::NPTH )
523 inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
524
525 m_holeCount++;
526 double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
527 m_averageHoleDiameter += static_cast<float>( holeDiameter * m_biuTo3Dunits );
528
529 createPadWithHole( pad, &m_TH_ODs, inflate );
530
532 createPadWithHole( pad, &m_viaAnnuli, inflate );
533
535 }
536 }
537
538 if( m_holeCount )
540
541 // Add contours of the pad holes (pads can be Circle or Segment holes)
542 for( FOOTPRINT* footprint : m_board->Footprints() )
543 {
544 for( PAD* pad : footprint->Pads() )
545 {
546 const VECTOR2I padHole = pad->GetDrillSize();
547
548 if( !padHole.x ) // Not drilled pad like SMD pad
549 continue;
550
551 // The hole in the body is inflated by copper thickness.
552 const int inflate = GetHolePlatingThickness();
553
554 if( pad->GetAttribute () != PAD_ATTRIB::NPTH )
555 {
557 pad->TransformHoleToPolygon( m_viaAnnuliPolys, inflate, maxError, ERROR_INSIDE );
558
559 pad->TransformHoleToPolygon( m_TH_ODPolys, inflate, maxError, ERROR_INSIDE );
560 }
561 else
562 {
563 // If not plated, no copper.
565 pad->TransformHoleToPolygon( m_viaAnnuliPolys, 0, maxError, ERROR_INSIDE );
566
567 pad->TransformHoleToPolygon( m_NPTH_ODPolys, 0, maxError, ERROR_INSIDE );
568 }
569 }
570 }
571
572 // Add footprints PADs objects to containers
573 for( PCB_LAYER_ID layer : layer_ids )
574 {
575 wxASSERT( m_layerMap.contains( layer ) );
576
577 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
578
579 // ADD PADS
580 for( FOOTPRINT* footprint : m_board->Footprints() )
581 {
582 addPads( footprint, layerContainer, layer );
583 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
584
585 if( cfg.DifferentiatePlatedCopper() && layer == F_Cu )
586 footprint->TransformPadsToPolySet( *m_frontPlatedCopperPolys, F_Cu, 0, maxError, ERROR_INSIDE );
587 else if( cfg.DifferentiatePlatedCopper() && layer == B_Cu )
588 footprint->TransformPadsToPolySet( *m_backPlatedCopperPolys, B_Cu, 0, maxError, ERROR_INSIDE );
589 }
590 }
591
592 // Add footprints PADs poly contours (vertical outlines)
593 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
594 {
595 for( PCB_LAYER_ID layer : layer_ids )
596 {
597 wxASSERT( m_layers_poly.contains( layer ) );
598
599 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
600
601 // Add pads to polygon list
602 for( FOOTPRINT* footprint : m_board->Footprints() )
603 {
604 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
605 transformFPShapesToPolySet( footprint, layer, *layerPoly, maxError, ERROR_INSIDE );
606 }
607 }
608 }
609
610 // Add graphic item on copper layers to object containers
611 for( PCB_LAYER_ID layer : layer_ids )
612 {
613 wxASSERT( m_layerMap.contains( layer ) );
614
615 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
616
617 // Add graphic items on copper layers (texts and other graphics)
618 for( BOARD_ITEM* item : m_board->Drawings() )
619 {
620 if( !item->IsOnLayer( layer ) )
621 continue;
622
623 switch( item->Type() )
624 {
625 case PCB_SHAPE_T:
626 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
627 break;
628
629 case PCB_TEXT_T:
630 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
631 break;
632
633 case PCB_TEXTBOX_T:
634 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
635 break;
636
637 case PCB_TABLE_T:
638 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
639 break;
640
642 case PCB_DIM_CENTER_T:
643 case PCB_DIM_RADIAL_T:
645 case PCB_DIM_LEADER_T:
646 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
647 break;
648
649 default:
650 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
651 item->Type() );
652 break;
653 }
654
655 // add also this shape to the plated copper polygon list if required
656 if( cfg.DifferentiatePlatedCopper() && ( layer == F_Cu || layer == B_Cu ) )
657 {
658 SHAPE_POLY_SET* copperPolys = layer == F_Cu ? m_frontPlatedCopperPolys
660
661 // Note: for TEXT and TEXTBOX, TransformShapeToPolygon returns the bounding
662 // box shape, not the exact text shape. So it is not used for these items
663 if( item->Type() == PCB_TEXTBOX_T )
664 {
665 PCB_TEXTBOX* text_box = static_cast<PCB_TEXTBOX*>( item );
666 text_box->TransformTextToPolySet( *copperPolys, 0, maxError, ERROR_INSIDE );
667 // Add box outlines
668 text_box->PCB_SHAPE::TransformShapeToPolygon( *copperPolys, layer, 0, maxError, ERROR_INSIDE );
669 }
670 else if( item->Type() == PCB_TEXT_T )
671 {
672 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
673 text->TransformTextToPolySet( *copperPolys, 0, maxError, ERROR_INSIDE );
674 }
675 else
676 {
677 item->TransformShapeToPolySet( *copperPolys, layer, 0, maxError, ERROR_INSIDE );
678 }
679 }
680 }
681 }
682
683 // Add graphic item on copper layers to poly contours (vertical outlines)
684 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
685 {
686 for( PCB_LAYER_ID layer : layer_ids )
687 {
688 wxASSERT( m_layers_poly.contains( layer ) );
689
690 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
691
692 // Add graphic items on copper layers (texts and other )
693 for( BOARD_ITEM* item : m_board->Drawings() )
694 {
695 if( !item->IsOnLayer( layer ) )
696 continue;
697
698 switch( item->Type() )
699 {
700 case PCB_SHAPE_T:
701 item->TransformShapeToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
702 break;
703
704 case PCB_TEXT_T:
705 {
706 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
707
708 text->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
709 break;
710 }
711
712 case PCB_TEXTBOX_T:
713 {
714 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
715
716 if( textbox->IsBorderEnabled() )
717 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
718
719 textbox->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
720 break;
721 }
722
723 case PCB_TABLE_T:
724 {
725 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
726
727 for( PCB_TABLECELL* cell : table->GetCells() )
728 cell->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
729
730 table->DrawBorders(
731 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
732 const STROKE_PARAMS& stroke )
733 {
734 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
735 seg.TransformToPolygon( *layerPoly, maxError, ERROR_INSIDE );
736 } );
737 break;
738 }
739
740 default:
741 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
742 item->Type() );
743 break;
744 }
745 }
746 }
747 }
748
749 if( cfg.show_zones )
750 {
751 if( aStatusReporter )
752 aStatusReporter->Report( _( "Create zones" ) );
753
754 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
755 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
756
757 for( ZONE* zone : m_board->Zones() )
758 {
759 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
760 {
761 zones.emplace_back( std::make_pair( zone, layer ) );
762 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
763
764 if( cfg.DifferentiatePlatedCopper() && layer == F_Cu )
765 zone->TransformShapeToPolygon( *m_frontPlatedCopperPolys, F_Cu, 0, maxError, ERROR_INSIDE );
766 else if( cfg.DifferentiatePlatedCopper() && layer == B_Cu )
767 zone->TransformShapeToPolygon( *m_backPlatedCopperPolys, B_Cu, 0, maxError, ERROR_INSIDE );
768 }
769 }
770
771 // Add zones objects
772 std::atomic<size_t> nextZone( 0 );
773 std::atomic<size_t> threadsFinished( 0 );
774
775 size_t parallelThreadCount = std::min<size_t>( zones.size(),
776 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
777
778 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
779 {
780 std::thread t = std::thread( [&]()
781 {
782 for( size_t areaId = nextZone.fetch_add( 1 );
783 areaId < zones.size();
784 areaId = nextZone.fetch_add( 1 ) )
785 {
786 ZONE* zone = zones[areaId].first;
787
788 if( zone == nullptr )
789 break;
790
791 PCB_LAYER_ID layer = zones[areaId].second;
792
793 if( m_layerMap.contains( layer ) )
794 addSolidAreasShapes( zone, m_layerMap[layer], layer );
795
796 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
797 && m_layers_poly.contains( layer ) )
798 {
799 auto mut_it = layer_lock.find( layer );
800
801 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
802 zone->TransformSolidAreasShapesToPolygon( layer, *m_layers_poly[layer] );
803 }
804 }
805
806 threadsFinished++;
807 } );
808
809 t.detach();
810 }
811
812 while( threadsFinished < parallelThreadCount )
813 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
814 }
815 // End Build Copper layers
816
817 // This will make a union of all added contours
818 m_TH_ODPolys.Simplify();
819 m_NPTH_ODPolys.Simplify();
820 m_viaTH_ODPolys.Simplify();
821 m_viaAnnuliPolys.Simplify();
822
823 // Build Tech layers
824 // Based on:
825 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
826 if( aStatusReporter )
827 aStatusReporter->Report( _( "Build Tech layers" ) );
828
829 // draw graphic items, on technical layers
830
831 LSEQ techLayerList = LSET::AllNonCuMask().Seq( {
832 B_Adhes,
833 F_Adhes,
834 B_Paste,
835 F_Paste,
836 B_SilkS,
837 F_SilkS,
838 B_Mask,
839 F_Mask,
840
841 // Aux Layers
842 Dwgs_User,
843 Cmts_User,
844 Eco1_User,
845 Eco2_User,
846 User_1,
847 User_2,
848 User_3,
849 User_4,
850 User_5,
851 User_6,
852 User_7,
853 User_8,
854 User_9,
855 User_10,
856 User_11,
857 User_12,
858 User_13,
859 User_14,
860 User_15,
861 User_16,
862 User_17,
863 User_18,
864 User_19,
865 User_20,
866 User_21,
867 User_22,
868 User_23,
869 User_24,
870 User_25,
871 User_26,
872 User_27,
873 User_28,
874 User_29,
875 User_30,
876 User_31,
877 User_32,
878 User_33,
879 User_34,
880 User_35,
881 User_36,
882 User_37,
883 User_38,
884 User_39,
885 User_40,
886 User_41,
887 User_42,
888 User_43,
889 User_44,
890 User_45,
891 } );
892
893 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
894
895 if( cfg.subtract_mask_from_silk || cfg.DifferentiatePlatedCopper() )
896 {
897 enabledFlags.set( LAYER_3D_SOLDERMASK_TOP );
898 enabledFlags.set( LAYER_3D_SOLDERMASK_BOTTOM );
899 }
900
901 for( PCB_LAYER_ID layer : techLayerList )
902 {
903 if( aStatusReporter )
904 aStatusReporter->Report( wxString::Format( _( "Build Tech layer %d" ), (int) layer ) );
905
906 if( !Is3dLayerEnabled( layer, enabledFlags ) )
907 continue;
908
909 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
910 m_layerMap[layer] = layerContainer;
911
912 SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
913 m_layers_poly[layer] = layerPoly;
914
915 if( Is3dLayerEnabled( layer, visibilityFlags ) )
916 {
917 // Add drawing objects
918 for( BOARD_ITEM* item : m_board->Drawings() )
919 {
920 if( !item->IsOnLayer( layer ) )
921 continue;
922
923 switch( item->Type() )
924 {
925 case PCB_SHAPE_T:
926 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item, layer );
927 break;
928
929 case PCB_TEXT_T:
930 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
931 break;
932
933 case PCB_TEXTBOX_T:
934 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
935 break;
936
937 case PCB_TABLE_T:
938 addTable( static_cast<PCB_TABLE*>( item ), layerContainer, item );
939 break;
940
942 case PCB_DIM_CENTER_T:
943 case PCB_DIM_RADIAL_T:
945 case PCB_DIM_LEADER_T:
946 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
947 break;
948
949 default:
950 break;
951 }
952 }
953
954 // Add track, via and arc tech layers
955 if( IsSolderMaskLayer( layer ) )
956 {
957 for( PCB_TRACK* track : m_board->Tracks() )
958 {
959 if( !track->IsOnLayer( layer ) )
960 continue;
961
962 // Only vias on a external copper layer can have a solder mask
963 PCB_LAYER_ID copper_layer = layer == F_Mask ? F_Cu : B_Cu;
964
965 if( track->Type() == PCB_VIA_T )
966 {
967 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
968
969 if( !via->FlashLayer( copper_layer ) )
970 continue;
971 }
972
973 int maskExpansion = track->GetSolderMaskExpansion();
974 createTrackWithMargin( track, layerContainer, layer, maskExpansion );
975 }
976 }
977
978 // Add footprints tech layers - objects
979 for( FOOTPRINT* footprint : m_board->Footprints() )
980 {
981 if( layer == F_SilkS || layer == B_SilkS )
982 {
983 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
984
985 for( PAD* pad : footprint->Pads() )
986 {
987 if( !pad->IsOnLayer( layer ) )
988 continue;
989
990 buildPadOutlineAsSegments( pad, layer, layerContainer, linewidth );
991 }
992 }
993 else
994 {
995 addPads( footprint, layerContainer, layer );
996 }
997
998 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
999 }
1000
1001 // Draw non copper zones
1002 if( cfg.show_zones )
1003 {
1004 for( ZONE* zone : m_board->Zones() )
1005 {
1006 if( zone->IsOnLayer( layer ) )
1007 addSolidAreasShapes( zone, layerContainer, layer );
1008 }
1009 }
1010 }
1011
1012 // Add item contours. We need these if we're building vertical walls or if this is a
1013 // mask layer and we're differentiating copper from plated copper.
1014 if( ( cfg.engine == RENDER_ENGINE::OPENGL && cfg.opengl_copper_thickness )
1015 || ( cfg.DifferentiatePlatedCopper() && ( layer == F_Mask || layer == B_Mask ) ) )
1016 {
1017 // DRAWINGS
1018 for( BOARD_ITEM* item : m_board->Drawings() )
1019 {
1020 if( !item->IsOnLayer( layer ) )
1021 continue;
1022
1023 switch( item->Type() )
1024 {
1025 case PCB_SHAPE_T:
1026 item->TransformShapeToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
1027 break;
1028
1029 case PCB_TEXT_T:
1030 {
1031 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
1032
1033 text->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
1034 break;
1035 }
1036
1037 case PCB_TEXTBOX_T:
1038 {
1039 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
1040
1041 if( textbox->IsBorderEnabled() )
1042 textbox->PCB_SHAPE::TransformShapeToPolygon( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
1043
1044 textbox->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
1045 break;
1046 }
1047
1048 case PCB_TABLE_T:
1049 {
1050 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
1051
1052 for( PCB_TABLECELL* cell : table->GetCells() )
1053 cell->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
1054
1055 table->DrawBorders(
1056 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB,
1057 const STROKE_PARAMS& stroke )
1058 {
1059 SHAPE_SEGMENT seg( ptA, ptB, stroke.GetWidth() );
1060 seg.TransformToPolygon( *layerPoly, maxError, ERROR_INSIDE );
1061 } );
1062
1063 break;
1064 }
1065
1066 default:
1067 break;
1068 }
1069 }
1070
1071 // NON-TENTED VIAS
1072 if( ( layer == F_Mask || layer == B_Mask ) )
1073 {
1074 int maskExpansion = GetBoard()->GetDesignSettings().m_SolderMaskExpansion;
1075
1076 for( PCB_TRACK* track : m_board->Tracks() )
1077 {
1078 if( track->Type() == PCB_VIA_T
1079 && static_cast<const PCB_VIA*>( track )->FlashLayer( layer )
1080 && !static_cast<const PCB_VIA*>( track )->IsTented( layer ) )
1081 {
1082 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, maxError, ERROR_INSIDE );
1083 }
1084 }
1085 }
1086
1087 // FOOTPRINT CHILDREN
1088 for( FOOTPRINT* footprint : m_board->Footprints() )
1089 {
1090 if( layer == F_SilkS || layer == B_SilkS )
1091 {
1092 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
1093
1094 for( PAD* pad : footprint->Pads() )
1095 {
1096 if( pad->IsOnLayer( layer ) )
1097 buildPadOutlineAsPolygon( pad, layer, *layerPoly, linewidth, maxError, ERROR_INSIDE );
1098 }
1099 }
1100 else
1101 {
1102 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
1103 }
1104
1105 transformFPTextToPolySet( footprint, layer, visibilityFlags, *layerPoly, maxError, ERROR_INSIDE );
1106 transformFPShapesToPolySet( footprint, layer, *layerPoly, maxError, ERROR_INSIDE );
1107 }
1108
1109 if( cfg.show_zones || layer == F_Mask || layer == B_Mask )
1110 {
1111 for( ZONE* zone : m_board->Zones() )
1112 {
1113 if( zone->IsOnLayer( layer ) )
1114 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
1115 }
1116 }
1117
1118 // This will make a union of all added contours
1119 layerPoly->Simplify();
1120 }
1121 }
1122 // End Build Tech layers
1123
1124 // If we're rendering off-board silk, also render pads of footprints which are entirely
1125 // outside the board outline. This makes off-board footprints more visually recognizable.
1126 if( cfg.show_off_board_silk )
1127 {
1128 BOX2I boardBBox = m_board_poly.BBox();
1129
1130 for( FOOTPRINT* footprint : m_board->Footprints() )
1131 {
1132 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1133 {
1134 if( footprint->IsFlipped() )
1135 addPads( footprint, m_offboardPadsBack, B_Cu );
1136 else
1137 addPads( footprint, m_offboardPadsFront, F_Cu );
1138 }
1139 }
1140
1141 m_offboardPadsFront->BuildBVH();
1142 m_offboardPadsBack->BuildBVH();
1143 }
1144
1145 // Simplify layer polygons
1146
1147 if( aStatusReporter )
1148 aStatusReporter->Report( _( "Simplifying copper layer polygons" ) );
1149
1150 if( cfg.DifferentiatePlatedCopper() )
1151 {
1152 if( aStatusReporter )
1153 aStatusReporter->Report( _( "Calculating plated copper" ) );
1154
1155 // TRIM PLATED COPPER TO SOLDERMASK
1156 if( m_layers_poly.contains( F_Mask ) )
1157 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( F_Mask ) );
1158
1159 if( m_layers_poly.contains( B_Mask ))
1160 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( B_Mask ) );
1161
1162 // Subtract plated copper from unplated copper
1163 if( m_layers_poly.contains( F_Cu ) )
1164 m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys );
1165
1166 if( m_layers_poly.contains( B_Cu ) )
1167 m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys );
1168
1169 // ADD PLATED COPPER
1170 ConvertPolygonToTriangles( *m_frontPlatedCopperPolys, *m_platedPadsFront, m_biuTo3Dunits,
1171 *m_board->GetItem( niluuid ) );
1172
1173 ConvertPolygonToTriangles( *m_backPlatedCopperPolys, *m_platedPadsBack, m_biuTo3Dunits,
1174 *m_board->GetItem( niluuid ) );
1175
1176 m_platedPadsFront->BuildBVH();
1177 m_platedPadsBack->BuildBVH();
1178 }
1179
1180 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
1181 {
1182 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1183 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1184
1185 if( cfg.DifferentiatePlatedCopper() )
1186 {
1187 layer_id_without_F_and_B.clear();
1188 layer_id_without_F_and_B.reserve( layer_ids.size() );
1189
1190 for( PCB_LAYER_ID layer: layer_ids )
1191 {
1192 if( layer != F_Cu && layer != B_Cu )
1193 layer_id_without_F_and_B.push_back( layer );
1194 }
1195
1196 selected_layer_id = layer_id_without_F_and_B;
1197 }
1198
1199 if( selected_layer_id.size() > 0 )
1200 {
1201 if( aStatusReporter )
1202 {
1203 aStatusReporter->Report( wxString::Format( _( "Simplifying %d copper layers" ),
1204 (int) selected_layer_id.size() ) );
1205 }
1206
1207 std::atomic<size_t> nextItem( 0 );
1208 std::atomic<size_t> threadsFinished( 0 );
1209
1210 size_t parallelThreadCount = std::min<size_t>(
1211 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1212 selected_layer_id.size() );
1213
1214 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1215 {
1216 std::thread t = std::thread(
1217 [&nextItem, &threadsFinished, &selected_layer_id, this]()
1218 {
1219 for( size_t i = nextItem.fetch_add( 1 );
1220 i < selected_layer_id.size();
1221 i = nextItem.fetch_add( 1 ) )
1222 {
1223 if( m_layers_poly.contains( selected_layer_id[i] ) )
1224 {
1225 // This will make a union of all added contours
1226 m_layers_poly[ selected_layer_id[i] ]->ClearArcs();
1227 m_layers_poly[ selected_layer_id[i] ]->Simplify();
1228 }
1229 }
1230
1231 threadsFinished++;
1232 } );
1233
1234 t.detach();
1235 }
1236
1237 while( threadsFinished < parallelThreadCount )
1238 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1239 }
1240 }
1241
1242 // Simplify holes polygon contours
1243 if( aStatusReporter )
1244 aStatusReporter->Report( _( "Simplify holes contours" ) );
1245
1246 for( PCB_LAYER_ID layer : layer_ids )
1247 {
1248 if( m_layerHoleOdPolys.contains( layer ) )
1249 {
1250 // found
1251 SHAPE_POLY_SET *polyLayer = m_layerHoleOdPolys[layer];
1252 polyLayer->Simplify();
1253
1254 wxASSERT( m_layerHoleIdPolys.contains( layer ) );
1255
1256 polyLayer = m_layerHoleIdPolys[layer];
1257 polyLayer->Simplify();
1258 }
1259 }
1260
1261 // Build BVH (Bounding volume hierarchy) for holes and vias
1262
1263 if( aStatusReporter )
1264 aStatusReporter->Report( _( "Build BVH for holes and vias" ) );
1265
1266 m_TH_IDs.BuildBVH();
1267 m_TH_ODs.BuildBVH();
1268 m_viaAnnuli.BuildBVH();
1269
1270 if( !m_layerHoleMap.empty() )
1271 {
1272 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1273 hole.second->BuildBVH();
1274 }
1275
1276 // We only need the Solder mask to initialize the BVH
1277 // because..?
1278 if( m_layerMap[B_Mask] )
1279 m_layerMap[B_Mask]->BuildBVH();
1280
1281 if( m_layerMap[F_Mask] )
1282 m_layerMap[F_Mask]->BuildBVH();
1283}
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Definition: approximation.h:32
@ ERROR_INSIDE
Definition: approximation.h:34
@ LAYER_CLASS_SILK
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
MAP_CONTAINER_2D_BASE m_layerHoleMap
Holes for each layer.
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
BVH_CONTAINER_2D * m_offboardPadsBack
void createLayers(REPORTER *aStatusReporter)
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
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)
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
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.
float m_averageHoleDiameter
SHAPE_POLY_SET m_viaTH_ODPolys
Via hole outer diameters.
BVH_CONTAINER_2D * m_platedPadsBack
void createPadWithHole(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aInflateValue)
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)
unsigned int m_holeCount
BVH_CONTAINER_2D m_viaAnnuli
List of via annular rings.
unsigned int m_copperLayersCount
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.
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:78
const ZONES & Zones() const
Definition: board.h:342
const FOOTPRINTS & Footprints() const
Definition: board.h:338
const TRACKS & Tracks() const
Definition: board.h:336
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:946
const DRAWINGS & Drawings() const
Definition: board.h:340
void Clear() override
void Add(OBJECT_2D *aObject)
Definition: container_2d.h:49
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:107
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:627
DRAWINGS & GraphicalItems()
Definition: footprint.h:214
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:583
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:297
Definition: pad.h:54
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:195
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:513
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1043
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:264
Abstract dimension API.
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 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.
Definition: pcb_track.cpp:2157
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pcb_track.cpp:1118
bool IsTented(PCB_LAYER_ID aLayer) const override
Checks if the given object is tented (its copper shape is covered by solder mask) on a given side of ...
Definition: pcb_track.cpp:1065
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
Definition: pcb_track.cpp:1385
int GetSolderMaskExpansion() const
Definition: pcb_track.cpp:1088
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)=0
Report a string with a given severity.
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 RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
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.
Definition: stroke_params.h:94
int GetWidth() const
Handle a list of polygons defining a copper zone.
Definition: zone.h:74
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.
KIID niluuid(0)
bool IsSolderMaskLayer(int aLayer)
Definition: layer_ids.h:733
@ LAYER_3D_SOLDERMASK_TOP
Definition: layer_ids.h:547
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:546
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition: layer_ids.h:265
@ LAYER_FP_TEXT
Definition: layer_ids.h:239
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition: layer_ids.h:262
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
VIATYPE
Definition: pcb_track.h:66
BOARD * GetBoard()
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...
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:249
@ 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:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ 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:103
@ 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_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ 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:104
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42