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