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 (C) 1992-2023 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
35#include "board_adapter.h"
36#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
39#include <footprint.h>
40#include <pad.h>
41#include <pcb_text.h>
42#include <pcb_textbox.h>
43#include <pcb_shape.h>
44#include <zone.h>
46#include <trigo.h>
47#include <vector>
48#include <thread>
49#include <core/arraydim.h>
50#include <algorithm>
51#include <atomic>
52#include <wx/log.h>
53
54#ifdef PRINT_STATISTICS_3D_VIEWER
55#include <core/profile.h>
56#endif
57
58
59
60
61/*
62 * This is used to draw pad outlines on silk layers.
63 */
64void buildPadOutlineAsPolygon( const PAD* aPad, SHAPE_POLY_SET& aBuffer, int aWidth, int aMaxError,
65 ERROR_LOC aErrorLoc )
66{
67 if( aPad->GetShape() == PAD_SHAPE::CIRCLE ) // Draw a ring
68 {
69 TransformRingToPolygon( aBuffer, aPad->ShapePos(), aPad->GetSize().x / 2, aWidth,
70 aMaxError, aErrorLoc );
71 }
72 else
73 {
74 // For other shapes, add outlines as thick segments in polygon buffer
75 const SHAPE_LINE_CHAIN& path = aPad->GetEffectivePolygon( ERROR_INSIDE )->COutline( 0 );
76
77 for( int ii = 0; ii < path.PointCount(); ++ii )
78 {
79 const VECTOR2I& a = path.CPoint( ii );
80 const VECTOR2I& b = path.CPoint( ii + 1 );
81
82 TransformOvalToPolygon( aBuffer, a, b, aWidth, aMaxError, aErrorLoc );
83 }
84 }
85}
86
87
88void transformFPShapesToPolySet( const FOOTPRINT* aFootprint, PCB_LAYER_ID aLayer,
89 SHAPE_POLY_SET& aBuffer, int aMaxError, ERROR_LOC aErrorLoc )
90{
91 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
92 {
93 if( item->Type() == PCB_SHAPE_T || BaseType( item->Type() ) == PCB_DIMENSION_T )
94 {
95 if( item->GetLayer() == aLayer )
96 item->TransformShapeToPolygon( aBuffer, aLayer, 0, aMaxError, aErrorLoc );
97 }
98 }
99}
100
101
103{
104#define DELETE_AND_FREE( ptr ) \
105 { \
106 delete ptr; \
107 ptr = nullptr; \
108 } \
109
110#define DELETE_AND_FREE_MAP( map ) \
111 { \
112 for( auto& [ layer, poly ] : map ) \
113 delete poly; \
114 \
115 map.clear(); \
116 }
117
119
124
127
132
135
140
141 m_TH_ODs.Clear();
142 m_TH_IDs.Clear();
145}
146
147
148void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
149{
151
152 // Build Copper layers
153 // Based on:
154 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L692
155
156#ifdef PRINT_STATISTICS_3D_VIEWER
157 unsigned stats_startCopperLayersTime = GetRunningMicroSecs();
158
159 unsigned start_Time = stats_startCopperLayersTime;
160#endif
161
164
166
167 std::bitset<LAYER_3D_END> visibilityFlags = GetVisibleLayers();
168
169 m_trackCount = 0;
171 m_viaCount = 0;
173 m_holeCount = 0;
175
176 if( !m_board )
177 return;
178
179 // Prepare track list, convert in a vector. Calc statistic for the holes
180 std::vector<const PCB_TRACK*> trackList;
181 trackList.clear();
182 trackList.reserve( m_board->Tracks().size() );
183
184 int maxError = m_board->GetDesignSettings().m_MaxError;
185
186 for( PCB_TRACK* track : m_board->Tracks() )
187 {
188 if( !Is3dLayerEnabled( track->GetLayer(), visibilityFlags ) ) // Skip non enabled layers
189 continue;
190
191 // Note: a PCB_TRACK holds normal segment tracks and also vias circles (that have also
192 // drill values)
193 trackList.push_back( track );
194
195 if( track->Type() == PCB_VIA_T )
196 {
197 const PCB_VIA *via = static_cast< const PCB_VIA*>( track );
198 m_viaCount++;
199 m_averageViaHoleDiameter += static_cast<float>( via->GetDrillValue() * m_biuTo3Dunits );
200 }
201 else
202 {
203 m_trackCount++;
204 }
205
206 m_averageTrackWidth += static_cast<float>( track->GetWidth() * m_biuTo3Dunits );
207 }
208
209 if( m_trackCount )
211
212 if( m_viaCount )
214
215 // Prepare copper layers index and containers
216 std::vector<PCB_LAYER_ID> layer_ids;
217 layer_ids.clear();
218 layer_ids.reserve( m_copperLayersCount );
219
220 for( unsigned i = 0; i < arrayDim( cu_seq ); ++i )
221 cu_seq[i] = ToLAYER_ID( B_Cu - i );
222
223 for( LSEQ cu = cu_set.Seq( cu_seq, arrayDim( cu_seq ) ); cu; ++cu )
224 {
225 const PCB_LAYER_ID layer = *cu;
226
227 if( !Is3dLayerEnabled( layer, visibilityFlags ) ) // Skip non enabled layers
228 continue;
229
230 layer_ids.push_back( layer );
231
232 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
233 m_layerMap[layer] = layerContainer;
234
235 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
236 {
237 SHAPE_POLY_SET* layerPoly = new SHAPE_POLY_SET;
238 m_layers_poly[layer] = layerPoly;
239 }
240 }
241
243 {
248
251 }
252
253 if( cfg.show_off_board_silk )
254 {
257 }
258
259 if( aStatusReporter )
260 aStatusReporter->Report( _( "Create tracks and vias" ) );
261
262 // Create tracks as objects and add it to container
263 for( PCB_LAYER_ID layer : layer_ids )
264 {
265 wxASSERT( m_layerMap.find( layer ) != m_layerMap.end() );
266
267 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
268
269 for( const PCB_TRACK* track : trackList )
270 {
271 // NOTE: Vias can be on multiple layers
272 if( !track->IsOnLayer( layer ) )
273 continue;
274
275 // Skip vias annulus when not flashed on this layer
276 if( track->Type() == PCB_VIA_T
277 && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
278 {
279 continue;
280 }
281
282 // Add object item to layer container
283 createTrack( track, layerContainer );
284 }
285 }
286
287 // Create VIAS and THTs objects and add it to holes containers
288 for( PCB_LAYER_ID layer : layer_ids )
289 {
290 // ADD TRACKS
291 unsigned int nTracks = trackList.size();
292
293 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
294 {
295 const PCB_TRACK *track = trackList[trackIdx];
296
297 if( !track->IsOnLayer( layer ) )
298 continue;
299
300 // ADD VIAS and THT
301 if( track->Type() == PCB_VIA_T )
302 {
303 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
304 const VIATYPE viatype = via->GetViaType();
305 const double holediameter = via->GetDrillValue() * BiuTo3dUnits();
306 const double viasize = via->GetWidth() * BiuTo3dUnits();
307 const double plating = GetHolePlatingThickness() * BiuTo3dUnits();
308
309 // holes and layer copper extend half info cylinder wall to hide transition
310 const float thickness = static_cast<float>( plating / 2.0f );
311 const float hole_inner_radius = static_cast<float>( holediameter / 2.0f );
312 const float ring_radius = static_cast<float>( viasize / 2.0f );
313
314 const SFVEC2F via_center( via->GetStart().x * m_biuTo3Dunits,
315 -via->GetStart().y * m_biuTo3Dunits );
316
317 if( viatype != VIATYPE::THROUGH )
318 {
319 // Add hole objects
320 BVH_CONTAINER_2D *layerHoleContainer = nullptr;
321
322 // Check if the layer is already created
323 if( m_layerHoleMap.find( layer ) == m_layerHoleMap.end() )
324 {
325 // not found, create a new container
326 layerHoleContainer = new BVH_CONTAINER_2D;
327 m_layerHoleMap[layer] = layerHoleContainer;
328 }
329 else
330 {
331 // found
332 layerHoleContainer = m_layerHoleMap[layer];
333 }
334
335 // Add a hole for this layer
336 layerHoleContainer->Add( new FILLED_CIRCLE_2D( via_center,
337 hole_inner_radius + thickness,
338 *track ) );
339 }
340 else if( layer == layer_ids[0] ) // it only adds once the THT holes
341 {
342 // Add through hole object
343 m_TH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness,
344 *track ) );
345 m_viaTH_ODs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius + thickness,
346 *track ) );
347
348 if( cfg.clip_silk_on_via_annuli && ring_radius > 0.0 )
349 m_viaAnnuli.Add( new FILLED_CIRCLE_2D( via_center, ring_radius, *track ) );
350
351 if( hole_inner_radius > 0.0 )
352 m_TH_IDs.Add( new FILLED_CIRCLE_2D( via_center, hole_inner_radius, *track ) );
353 }
354 }
355
356 if( cfg.differentiate_plated_copper && layer == F_Cu )
357 {
359 ERROR_INSIDE );
360 }
361 else if( cfg.differentiate_plated_copper && layer == B_Cu )
362 {
364 ERROR_INSIDE );
365 }
366 }
367 }
368
369 // Create VIAS and THTs objects and add it to holes containers
370 for( PCB_LAYER_ID layer : layer_ids )
371 {
372 // ADD TRACKS
373 const unsigned int nTracks = trackList.size();
374
375 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
376 {
377 const PCB_TRACK *track = trackList[trackIdx];
378
379 if( !track->IsOnLayer( layer ) )
380 continue;
381
382 // ADD VIAS and THT
383 if( track->Type() == PCB_VIA_T )
384 {
385 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
386 const VIATYPE viatype = via->GetViaType();
387
388 if( viatype != VIATYPE::THROUGH )
389 {
390 // Add PCB_VIA hole contours
391
392 // Add outer holes of VIAs
393 SHAPE_POLY_SET *layerOuterHolesPoly = nullptr;
394 SHAPE_POLY_SET *layerInnerHolesPoly = nullptr;
395
396 // Check if the layer is already created
397 if( m_layerHoleOdPolys.find( layer ) == m_layerHoleOdPolys.end() )
398 {
399 // not found, create a new container
400 layerOuterHolesPoly = new SHAPE_POLY_SET;
401 m_layerHoleOdPolys[layer] = layerOuterHolesPoly;
402
403 wxASSERT( m_layerHoleIdPolys.find( layer ) == m_layerHoleIdPolys.end() );
404
405 layerInnerHolesPoly = new SHAPE_POLY_SET;
406 m_layerHoleIdPolys[layer] = layerInnerHolesPoly;
407 }
408 else
409 {
410 // found
411 layerOuterHolesPoly = m_layerHoleOdPolys[layer];
412
413 wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
414
415 layerInnerHolesPoly = m_layerHoleIdPolys[layer];
416 }
417
418 const int holediameter = via->GetDrillValue();
419 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
420
421 TransformCircleToPolygon( *layerOuterHolesPoly, via->GetStart(),
422 hole_outer_radius, maxError, ERROR_INSIDE );
423
424 TransformCircleToPolygon( *layerInnerHolesPoly, via->GetStart(),
425 holediameter / 2, maxError, ERROR_INSIDE );
426 }
427 else if( layer == layer_ids[0] ) // it only adds once the THT holes
428 {
429 const int holediameter = via->GetDrillValue();
430 const int hole_outer_radius = (holediameter / 2) + GetHolePlatingThickness();
431 const int hole_outer_ring_radius = KiROUND( via->GetWidth() / 2.0 );
432
433 // Add through hole contours
434 TransformCircleToPolygon( m_TH_ODPolys, via->GetStart(), hole_outer_radius,
435 maxError, ERROR_INSIDE );
436
437 // Add same thing for vias only
438 TransformCircleToPolygon( m_viaTH_ODPolys, via->GetStart(), hole_outer_radius,
439 maxError, ERROR_INSIDE );
440
442 {
444 hole_outer_ring_radius, maxError, ERROR_INSIDE );
445 }
446 }
447 }
448 }
449 }
450
451 // Creates vertical outline contours of the tracks and add it to the poly of the layer
452 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
453 {
454 for( PCB_LAYER_ID layer : layer_ids )
455 {
456 wxASSERT( m_layers_poly.find( layer ) != m_layers_poly.end() );
457
458 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
459
460 // ADD TRACKS
461 unsigned int nTracks = trackList.size();
462
463 for( unsigned int trackIdx = 0; trackIdx < nTracks; ++trackIdx )
464 {
465 const PCB_TRACK *track = trackList[trackIdx];
466
467 if( !track->IsOnLayer( layer ) )
468 continue;
469
470 // Skip vias annulus when not flashed on this layer
471 if( track->Type() == PCB_VIA_T
472 && !static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
473 {
474 continue;
475 }
476
477 // Add the track/via contour
478 track->TransformShapeToPolygon( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
479 }
480 }
481 }
482
483 // Add holes of footprints
484 for( FOOTPRINT* footprint : m_board->Footprints() )
485 {
486 for( PAD* pad : footprint->Pads() )
487 {
488 const VECTOR2I padHole = pad->GetDrillSize();
489
490 if( !padHole.x ) // Not drilled pad like SMD pad
491 continue;
492
493 // The hole in the body is inflated by copper thickness, if not plated, no copper
494 int inflate = 0;
495
496 if( pad->GetAttribute () != PAD_ATTRIB::NPTH )
497 inflate = KiROUND( GetHolePlatingThickness() / 2.0 );
498
499 m_holeCount++;
500 double holeDiameter = ( pad->GetDrillSize().x + pad->GetDrillSize().y ) / 2.0;
501 m_averageHoleDiameter += static_cast<float>( holeDiameter * m_biuTo3Dunits );
502
503 createPadWithHole( pad, &m_TH_ODs, inflate );
504
506 createPadWithHole( pad, &m_viaAnnuli, inflate );
507
509 }
510 }
511
512 if( m_holeCount )
514
515 // Add contours of the pad holes (pads can be Circle or Segment holes)
516 for( FOOTPRINT* footprint : m_board->Footprints() )
517 {
518 for( PAD* pad : footprint->Pads() )
519 {
520 const VECTOR2I padHole = pad->GetDrillSize();
521
522 if( !padHole.x ) // Not drilled pad like SMD pad
523 continue;
524
525 // The hole in the body is inflated by copper thickness.
526 const int inflate = GetHolePlatingThickness();
527
528 if( pad->GetAttribute () != PAD_ATTRIB::NPTH )
529 {
531 pad->TransformHoleToPolygon( m_viaAnnuliPolys, inflate, maxError, ERROR_INSIDE );
532
533 pad->TransformHoleToPolygon( m_TH_ODPolys, inflate, maxError, ERROR_INSIDE );
534 }
535 else
536 {
537 // If not plated, no copper.
539 pad->TransformHoleToPolygon( m_viaAnnuliPolys, 0, maxError, ERROR_INSIDE );
540
541 pad->TransformHoleToPolygon( m_NPTH_ODPolys, 0, maxError, ERROR_INSIDE );
542 }
543 }
544 }
545
546 // Add footprints PADs objects to containers
547 for( PCB_LAYER_ID layer : layer_ids )
548 {
549 wxASSERT( m_layerMap.find( layer ) != m_layerMap.end() );
550
551 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
552
553 // ADD PADS
554 for( FOOTPRINT* footprint : m_board->Footprints() )
555 {
556 addPads( footprint, layerContainer, layer, cfg.differentiate_plated_copper, false );
557
558 // Micro-wave footprints may have items on copper layers
559 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
560 }
561 }
562
563 // Add footprints PADs poly contours (vertical outlines)
564 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
565 {
566 for( PCB_LAYER_ID layer : layer_ids )
567 {
568 wxASSERT( m_layers_poly.find( layer ) != m_layers_poly.end() );
569
570 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
571
572 // Add pads to polygon list
573 for( FOOTPRINT* footprint : m_board->Footprints() )
574 {
575 // Note: NPTH pads are not drawn on copper layers when the pad has same shape as
576 // its hole
577 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE,
578 true, cfg.differentiate_plated_copper, false );
579
580 transformFPShapesToPolySet( footprint, layer, *layerPoly, maxError, ERROR_INSIDE );
581 }
582 }
583
585 {
586 // ADD PLATED PADS contours
587 for( FOOTPRINT* footprint : m_board->Footprints() )
588 {
589 footprint->TransformPadsToPolySet( *m_frontPlatedPadPolys, F_Cu, 0, maxError,
590 ERROR_INSIDE, true, false, true );
591
592 footprint->TransformPadsToPolySet( *m_backPlatedPadPolys, B_Cu, 0, maxError,
593 ERROR_INSIDE, true, false, true );
594 }
595 }
596 }
597
598 // Add graphic item on copper layers to object containers
599 for( PCB_LAYER_ID layer : layer_ids )
600 {
601 wxASSERT( m_layerMap.find( layer ) != m_layerMap.end() );
602
603 BVH_CONTAINER_2D *layerContainer = m_layerMap[layer];
604
605 // Add graphic items on copper layers (texts and other graphics)
606 for( BOARD_ITEM* item : m_board->Drawings() )
607 {
608 if( !item->IsOnLayer( layer ) )
609 continue;
610
611 switch( item->Type() )
612 {
613 case PCB_SHAPE_T:
614 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item );
615 break;
616
617 case PCB_TEXT_T:
618 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
619 break;
620
621 case PCB_TEXTBOX_T:
622 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
623 break;
624
626 case PCB_DIM_CENTER_T:
627 case PCB_DIM_RADIAL_T:
629 case PCB_DIM_LEADER_T:
630 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
631 break;
632
633 default:
634 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
635 item->Type() );
636 break;
637 }
638 }
639 }
640
641 // Add graphic item on copper layers to poly contours (vertical outlines)
642 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
643 {
644 for( PCB_LAYER_ID layer : layer_ids )
645 {
646 wxASSERT( m_layers_poly.find( layer ) != m_layers_poly.end() );
647
648 SHAPE_POLY_SET *layerPoly = m_layers_poly[layer];
649
650 // Add graphic items on copper layers (texts and other )
651 for( BOARD_ITEM* item : m_board->Drawings() )
652 {
653 if( !item->IsOnLayer( layer ) )
654 continue;
655
656 switch( item->Type() )
657 {
658 case PCB_SHAPE_T:
659 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
660 break;
661
662 case PCB_TEXT_T:
663 {
664 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
665
666 text->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
667 break;
668 }
669
670 case PCB_TEXTBOX_T:
671 {
672 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
673
674 textbox->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
675 break;
676 }
677
678 default:
679 wxLogTrace( m_logTrace, wxT( "createLayers: item type: %d not implemented" ),
680 item->Type() );
681 break;
682 }
683 }
684 }
685 }
686
687 if( cfg.show_zones )
688 {
689 if( aStatusReporter )
690 aStatusReporter->Report( _( "Create zones" ) );
691
692 std::vector<std::pair<ZONE*, PCB_LAYER_ID>> zones;
693 std::unordered_map<PCB_LAYER_ID, std::unique_ptr<std::mutex>> layer_lock;
694
695 for( ZONE* zone : m_board->Zones() )
696 {
697 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
698 {
699 zones.emplace_back( std::make_pair( zone, layer ) );
700 layer_lock.emplace( layer, std::make_unique<std::mutex>() );
701
702 if( cfg.differentiate_plated_copper && layer == F_Cu )
703 {
704 zone->TransformShapeToPolygon( *m_frontPlatedCopperPolys, F_Cu, 0, maxError,
705 ERROR_INSIDE );
706 }
707 else if( cfg.differentiate_plated_copper && layer == B_Cu )
708 {
709 zone->TransformShapeToPolygon( *m_backPlatedCopperPolys, B_Cu, 0, maxError,
710 ERROR_INSIDE );
711 }
712 }
713 }
714
715 // Add zones objects
716 std::atomic<size_t> nextZone( 0 );
717 std::atomic<size_t> threadsFinished( 0 );
718
719 size_t parallelThreadCount = std::min<size_t>( zones.size(),
720 std::max<size_t>( std::thread::hardware_concurrency(), 2 ) );
721
722 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
723 {
724 std::thread t = std::thread( [&]()
725 {
726 for( size_t areaId = nextZone.fetch_add( 1 );
727 areaId < zones.size();
728 areaId = nextZone.fetch_add( 1 ) )
729 {
730 ZONE* zone = zones[areaId].first;
731
732 if( zone == nullptr )
733 break;
734
735 PCB_LAYER_ID layer = zones[areaId].second;
736
737 auto layerContainer = m_layerMap.find( layer );
738 auto layerPolyContainer = m_layers_poly.find( layer );
739
740 if( layerContainer != m_layerMap.end() )
741 addSolidAreasShapes( zone, layerContainer->second, layer );
742
743 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL
744 && layerPolyContainer != m_layers_poly.end() )
745 {
746 auto mut_it = layer_lock.find( layer );
747
748 std::lock_guard< std::mutex > lock( *( mut_it->second ) );
749 zone->TransformSolidAreasShapesToPolygon( layer, *layerPolyContainer->second );
750 }
751 }
752
753 threadsFinished++;
754 } );
755
756 t.detach();
757 }
758
759 while( threadsFinished < parallelThreadCount )
760 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
761 }
762 // End Build Copper layers
763
764 // This will make a union of all added contours
765 m_TH_ODPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
766 m_NPTH_ODPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
767 m_viaTH_ODPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
768 m_viaAnnuliPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
769
770 // Build Tech layers
771 // Based on:
772 // https://github.com/KiCad/kicad-source-mirror/blob/master/3d-viewer/3d_draw.cpp#L1059
773 if( aStatusReporter )
774 aStatusReporter->Report( _( "Build Tech layers" ) );
775
776 // draw graphic items, on technical layers
777
778 static const PCB_LAYER_ID techLayerList[] = {
779 B_Adhes,
780 F_Adhes,
781 B_Paste,
782 F_Paste,
783 B_SilkS,
784 F_SilkS,
785 B_Mask,
786 F_Mask,
787
788 // Aux Layers
789 Dwgs_User,
790 Cmts_User,
791 Eco1_User,
793 };
794
795 std::bitset<LAYER_3D_END> enabledFlags = visibilityFlags;
796
797 if( cfg.subtract_mask_from_silk || cfg.differentiate_plated_copper )
798 {
799 enabledFlags.set( LAYER_3D_SOLDERMASK_TOP );
800 enabledFlags.set( LAYER_3D_SOLDERMASK_BOTTOM );
801 }
802
803 for( PCB_LAYER_ID layer : LSET::AllNonCuMask().Seq( techLayerList, arrayDim( techLayerList ) ) )
804 {
805 if( aStatusReporter )
806 aStatusReporter->Report( wxString::Format( _( "Build Tech layer %d" ), (int) layer ) );
807
808 if( !Is3dLayerEnabled( layer, enabledFlags ) )
809 continue;
810
811 BVH_CONTAINER_2D *layerContainer = new BVH_CONTAINER_2D;
812 m_layerMap[layer] = layerContainer;
813
814 SHAPE_POLY_SET *layerPoly = new SHAPE_POLY_SET;
815 m_layers_poly[layer] = layerPoly;
816
817 if( Is3dLayerEnabled( layer, visibilityFlags ) )
818 {
819 // Add drawing objects
820 for( BOARD_ITEM* item : m_board->Drawings() )
821 {
822 if( !item->IsOnLayer( layer ) )
823 continue;
824
825 switch( item->Type() )
826 {
827 case PCB_SHAPE_T:
828 addShape( static_cast<PCB_SHAPE*>( item ), layerContainer, item );
829 break;
830
831 case PCB_TEXT_T:
832 addText( static_cast<PCB_TEXT*>( item ), layerContainer, item );
833 break;
834
835 case PCB_TEXTBOX_T:
836 addShape( static_cast<PCB_TEXTBOX*>( item ), layerContainer, item );
837 break;
838
840 case PCB_DIM_CENTER_T:
841 case PCB_DIM_RADIAL_T:
843 case PCB_DIM_LEADER_T:
844 addShape( static_cast<PCB_DIMENSION_BASE*>( item ), layerContainer, item );
845 break;
846
847 default:
848 break;
849 }
850 }
851
852 // Add via tech layers
853 if( ( layer == F_Mask || layer == B_Mask ) && !m_board->GetTentVias() )
854 {
855 int maskExpansion = GetBoard()->GetDesignSettings().m_SolderMaskExpansion;
856
857 for( PCB_TRACK* track : m_board->Tracks() )
858 {
859 if( track->Type() == PCB_VIA_T
860 && static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
861 {
862 createViaWithMargin( track, layerContainer, maskExpansion );
863 }
864 }
865 }
866
867 // Add footprints tech layers - objects
868 for( FOOTPRINT* footprint : m_board->Footprints() )
869 {
870 if( layer == F_SilkS || layer == B_SilkS )
871 {
872 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
873
874 for( PAD* pad : footprint->Pads() )
875 {
876 if( !pad->IsOnLayer( layer ) )
877 continue;
878
879 buildPadOutlineAsSegments( pad, layerContainer, linewidth );
880 }
881 }
882 else
883 {
884 addPads( footprint, layerContainer, layer, false, false );
885 }
886
887 addFootprintShapes( footprint, layerContainer, layer, visibilityFlags );
888 }
889
890 // Draw non copper zones
891 if( cfg.show_zones )
892 {
893 for( ZONE* zone : m_board->Zones() )
894 {
895 if( zone->IsOnLayer( layer ) )
896 addSolidAreasShapes( zone, layerContainer, layer );
897 }
898 }
899 }
900
901 // Add item contours. We need these if we're building vertical walls or if this is a
902 // mask layer and we're differentiating copper from plated copper.
903 if( ( cfg.engine == RENDER_ENGINE::OPENGL && cfg.opengl_copper_thickness )
904 || ( cfg.differentiate_plated_copper && ( layer == F_Mask || layer == B_Mask ) ) )
905 {
906 // DRAWINGS
907 for( BOARD_ITEM* item : m_board->Drawings() )
908 {
909 if( !item->IsOnLayer( layer ) )
910 continue;
911
912 switch( item->Type() )
913 {
914 case PCB_SHAPE_T:
915 item->TransformShapeToPolygon( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
916 break;
917
918 case PCB_TEXT_T:
919 {
920 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
921
922 text->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
923 break;
924 }
925
926 case PCB_TEXTBOX_T:
927 {
928 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
929
930 textbox->TransformTextToPolySet( *layerPoly, 0, maxError, ERROR_INSIDE );
931 break;
932 }
933
934 default:
935 break;
936 }
937 }
938
939 // NON-TENTED VIAS
940 if( ( layer == F_Mask || layer == B_Mask ) && !m_board->GetTentVias() )
941 {
942 int maskExpansion = GetBoard()->GetDesignSettings().m_SolderMaskExpansion;
943
944 for( PCB_TRACK* track : m_board->Tracks() )
945 {
946 if( track->Type() == PCB_VIA_T
947 && static_cast<const PCB_VIA*>( track )->FlashLayer( layer ) )
948 {
949 track->TransformShapeToPolygon( *layerPoly, layer, maskExpansion, maxError,
950 ERROR_INSIDE );
951 }
952 }
953 }
954
955 // FOOTPRINT CHILDREN
956 for( FOOTPRINT* footprint : m_board->Footprints() )
957 {
958 if( layer == F_SilkS || layer == B_SilkS )
959 {
960 int linewidth = m_board->GetDesignSettings().m_LineThickness[ LAYER_CLASS_SILK ];
961
962 for( PAD* pad : footprint->Pads() )
963 {
964 if( pad->IsOnLayer( layer ) )
965 {
966 buildPadOutlineAsPolygon( pad, *layerPoly, linewidth, maxError,
967 ERROR_INSIDE );
968 }
969 }
970 }
971 else
972 {
973 footprint->TransformPadsToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
974 }
975
976 // On tech layers, use a poor circle approximation, only for texts (stroke font)
977 footprint->TransformFPTextToPolySet( *layerPoly, layer, 0, maxError, ERROR_INSIDE );
978
979 // Add the remaining things with dynamic seg count for circles
980 transformFPShapesToPolySet( footprint, layer, *layerPoly, maxError, ERROR_INSIDE );
981 }
982
983 if( cfg.show_zones || layer == F_Mask || layer == B_Mask )
984 {
985 for( ZONE* zone : m_board->Zones() )
986 {
987 if( zone->IsOnLayer( layer ) )
988 zone->TransformSolidAreasShapesToPolygon( layer, *layerPoly );
989 }
990 }
991
992 // This will make a union of all added contours
993 layerPoly->Simplify( SHAPE_POLY_SET::PM_FAST );
994 }
995 }
996 // End Build Tech layers
997
998 // If we're rendering off-board silk, also render pads of footprints which are entirely
999 // outside the board outline. This makes off-board footprints more visually recognizable.
1000 if( cfg.show_off_board_silk )
1001 {
1002 BOX2I boardBBox = m_board_poly.BBox();
1003
1004 for( FOOTPRINT* footprint : m_board->Footprints() )
1005 {
1006 if( !footprint->GetBoundingBox().Intersects( boardBBox ) )
1007 {
1008 if( footprint->IsFlipped() )
1009 addPads( footprint, m_offboardPadsBack, B_Cu, false, false );
1010 else
1011 addPads( footprint, m_offboardPadsFront, F_Cu, false, false );
1012 }
1013 }
1014
1015 m_offboardPadsFront->BuildBVH();
1016 m_offboardPadsBack->BuildBVH();
1017 }
1018
1019 // Simplify layer polygons
1020
1021 if( aStatusReporter )
1022 aStatusReporter->Report( _( "Simplifying copper layer polygons" ) );
1023
1024 if( cfg.differentiate_plated_copper )
1025 {
1026 if( aStatusReporter )
1027 aStatusReporter->Report( _( "Calculating plated copper" ) );
1028
1029 // TRIM PLATED COPPER TO SOLDERMASK
1030 if( m_layers_poly.find( F_Mask ) != m_layers_poly.end() )
1031 {
1032 m_frontPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( F_Mask ),
1034 }
1035
1036 if( m_layers_poly.find( B_Mask ) != m_layers_poly.end() )
1037 {
1038 m_backPlatedCopperPolys->BooleanIntersection( *m_layers_poly.at( B_Mask ),
1040 }
1041
1042 // SUBTRACT PLATED COPPER FROM (UNPLATED) COPPER
1043 if( m_layers_poly.find( F_Cu ) != m_layers_poly.end() )
1044 {
1045 m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedPadPolys, SHAPE_POLY_SET::PM_FAST );
1046 m_layers_poly[F_Cu]->BooleanSubtract( *m_frontPlatedCopperPolys, SHAPE_POLY_SET::PM_FAST );
1047 }
1048
1049 if( m_layers_poly.find( B_Cu ) != m_layers_poly.end() )
1050 {
1051 m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedPadPolys, SHAPE_POLY_SET::PM_FAST );
1052 m_layers_poly[B_Cu]->BooleanSubtract( *m_backPlatedCopperPolys, SHAPE_POLY_SET::PM_FAST );
1053 }
1054
1055 m_frontPlatedPadPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
1056 m_backPlatedPadPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
1057 m_frontPlatedCopperPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
1058 m_backPlatedCopperPolys->Simplify( SHAPE_POLY_SET::PM_FAST );
1059
1060 // ADD PLATED PADS
1061 for( FOOTPRINT* footprint : m_board->Footprints() )
1062 {
1063 addPads( footprint, m_platedPadsFront, F_Cu, false, true );
1064 addPads( footprint, m_platedPadsBack, B_Cu, false, true );
1065 }
1066
1067 // ADD PLATED COPPER
1068 ConvertPolygonToTriangles( *m_frontPlatedCopperPolys, *m_platedPadsFront, m_biuTo3Dunits,
1069 *m_board->GetItem( niluuid ) );
1070
1071 ConvertPolygonToTriangles( *m_backPlatedCopperPolys, *m_platedPadsBack, m_biuTo3Dunits,
1072 *m_board->GetItem( niluuid ) );
1073
1074 m_platedPadsFront->BuildBVH();
1075 m_platedPadsBack->BuildBVH();
1076 }
1077
1078 if( cfg.opengl_copper_thickness && cfg.engine == RENDER_ENGINE::OPENGL )
1079 {
1080 std::vector<PCB_LAYER_ID> &selected_layer_id = layer_ids;
1081 std::vector<PCB_LAYER_ID> layer_id_without_F_and_B;
1082
1083 if( cfg.differentiate_plated_copper )
1084 {
1085 layer_id_without_F_and_B.clear();
1086 layer_id_without_F_and_B.reserve( layer_ids.size() );
1087
1088 for( PCB_LAYER_ID layer: layer_ids )
1089 {
1090 if( layer != F_Cu && layer != B_Cu )
1091 layer_id_without_F_and_B.push_back( layer );
1092 }
1093
1094 selected_layer_id = layer_id_without_F_and_B;
1095 }
1096
1097 if( selected_layer_id.size() > 0 )
1098 {
1099 if( aStatusReporter )
1100 {
1101 aStatusReporter->Report( wxString::Format( _( "Simplifying %d copper layers" ),
1102 (int) selected_layer_id.size() ) );
1103 }
1104
1105 std::atomic<size_t> nextItem( 0 );
1106 std::atomic<size_t> threadsFinished( 0 );
1107
1108 size_t parallelThreadCount = std::min<size_t>(
1109 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
1110 selected_layer_id.size() );
1111
1112 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1113 {
1114 std::thread t = std::thread(
1115 [&nextItem, &threadsFinished, &selected_layer_id, this]()
1116 {
1117 for( size_t i = nextItem.fetch_add( 1 );
1118 i < selected_layer_id.size();
1119 i = nextItem.fetch_add( 1 ) )
1120 {
1121 auto layerPoly = m_layers_poly.find( selected_layer_id[i] );
1122
1123 if( layerPoly != m_layers_poly.end() )
1124 {
1125 // This will make a union of all added contours
1126 layerPoly->second->Simplify( SHAPE_POLY_SET::PM_FAST );
1127 }
1128 }
1129
1130 threadsFinished++;
1131 } );
1132
1133 t.detach();
1134 }
1135
1136 while( threadsFinished < parallelThreadCount )
1137 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1138 }
1139 }
1140
1141 // Simplify holes polygon contours
1142 if( aStatusReporter )
1143 aStatusReporter->Report( _( "Simplify holes contours" ) );
1144
1145 for( PCB_LAYER_ID layer : layer_ids )
1146 {
1147 if( m_layerHoleOdPolys.find( layer ) != m_layerHoleOdPolys.end() )
1148 {
1149 // found
1150 SHAPE_POLY_SET *polyLayer = m_layerHoleOdPolys[layer];
1151 polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
1152
1153 wxASSERT( m_layerHoleIdPolys.find( layer ) != m_layerHoleIdPolys.end() );
1154
1155 polyLayer = m_layerHoleIdPolys[layer];
1156 polyLayer->Simplify( SHAPE_POLY_SET::PM_FAST );
1157 }
1158 }
1159
1160 // Build BVH (Bounding volume hierarchy) for holes and vias
1161
1162 if( aStatusReporter )
1163 aStatusReporter->Report( _( "Build BVH for holes and vias" ) );
1164
1165 m_TH_IDs.BuildBVH();
1166 m_TH_ODs.BuildBVH();
1167 m_viaAnnuli.BuildBVH();
1168
1169 if( !m_layerHoleMap.empty() )
1170 {
1171 for( std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& hole : m_layerHoleMap )
1172 hole.second->BuildBVH();
1173 }
1174
1175 // We only need the Solder mask to initialize the BVH
1176 // because..?
1177 if( m_layerMap[B_Mask] )
1178 m_layerMap[B_Mask]->BuildBVH();
1179
1180 if( m_layerMap[F_Mask] )
1181 m_layerMap[F_Mask]->BuildBVH();
1182}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
@ LAYER_CLASS_SILK
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.
unsigned int m_viaCount
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.
void addPads(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId, bool aSkipPlatedPads, bool aSkipNonPlatedPads)
BVH_CONTAINER_2D * m_platedPadsBack
void createPadWithHole(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aInflateValue)
void addShape(const PCB_SHAPE *aShape, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner)
void createTrack(const PCB_TRACK *aTrack, CONTAINER_2D_BASE *aDstContainer)
MAP_POLY m_layers_poly
Amalgamated polygon contours for various types of items.
SHAPE_POLY_SET * m_backPlatedCopperPolys
SHAPE_POLY_SET * m_backPlatedPadPolys
EDA_3D_VIEWER_SETTINGS * m_Cfg
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
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....
SHAPE_POLY_SET * m_frontPlatedPadPolys
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:77
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition: board_item.h:290
ZONES & Zones()
Definition: board.h:324
FOOTPRINTS & Footprints()
Definition: board.h:318
TRACKS & Tracks()
Definition: board.h:315
DRAWINGS & Drawings()
Definition: board.h:321
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:766
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:97
DRAWINGS & GraphicalItems()
Definition: footprint.h:191
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:513
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:556
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition: lset.cpp:803
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:782
Definition: pad.h:59
VECTOR2I ShapePos() const
Definition: pad.cpp:761
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:359
PAD_SHAPE GetShape() const
Definition: pad.h:190
const VECTOR2I & GetSize() const
Definition: pad.h:244
Abstract dimension API.
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:1426
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
Definition: pcb_track.cpp:801
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
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(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
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.
void buildPadOutlineAsPolygon(const PAD *aPad, SHAPE_POLY_SET &aBuffer, int aWidth, int aMaxError, ERROR_LOC aErrorLoc)
#define DELETE_AND_FREE_MAP(map)
void transformFPShapesToPolySet(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer, int aMaxError, ERROR_LOC aErrorLoc)
#define DELETE_AND_FREE(ptr)
#define _(s)
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_INSIDE
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
KIID niluuid(0)
@ LAYER_3D_SOLDERMASK_TOP
Definition: layer_ids.h:451
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition: layer_ids.h:450
#define MAX_CU_LAYERS
Definition: layer_ids.h:141
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Adhes
Definition: layer_ids.h:98
@ Dwgs_User
Definition: layer_ids.h:110
@ F_Paste
Definition: layer_ids.h:102
@ Cmts_User
Definition: layer_ids.h:111
@ F_Adhes
Definition: layer_ids.h:99
@ B_Mask
Definition: layer_ids.h:107
@ B_Cu
Definition: layer_ids.h:96
@ Eco1_User
Definition: layer_ids.h:112
@ F_Mask
Definition: layer_ids.h:108
@ B_Paste
Definition: layer_ids.h:101
@ F_SilkS
Definition: layer_ids.h:105
@ Eco2_User
Definition: layer_ids.h:113
@ B_SilkS
Definition: layer_ids.h:104
@ F_Cu
Definition: layer_ids.h:65
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:941
VIATYPE
Definition: pcb_track.h:64
BOARD * GetBoard()
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
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:253
@ 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:103
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:100
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:95
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:101
@ 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:99
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
Definition: typeinfo.h:98
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:102
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42