KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_painter.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) 2013-2019 CERN
5 * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
8 * @author Maciej Suminski <[email protected]>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28#include <board.h>
30#include <pcb_track.h>
31#include <pcb_group.h>
32#include <footprint.h>
33#include <pad.h>
34#include <pcb_shape.h>
35#include <string_utils.h>
36#include <zone.h>
37#include <pcb_reference_image.h>
38#include <pcb_text.h>
39#include <pcb_textbox.h>
40#include <pcb_table.h>
41#include <pcb_tablecell.h>
42#include <pcb_marker.h>
43#include <pcb_dimension.h>
44#include <pcb_target.h>
45
46#include <layer_ids.h>
47#include <lset.h>
48#include <pcb_painter.h>
49#include <pcb_display_options.h>
55#include <pcbnew_settings.h>
57
60#include <callback_gal.h>
63#include <geometry/shape_rect.h>
67#include <bezier_curves.h>
68#include <kiface_base.h>
69#include <gr_text.h>
70#include <pgm_base.h>
71
72using namespace KIGFX;
73
74
76{
77 return dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() );
78}
79
80// Helpers for display options existing in Cvpcb and Pcbnew
81// Note, when running Cvpcb, pcbconfig() returns nullptr and viewer_settings()
82// returns the viewer options existing to Cvpcb and Pcbnew
84{
85 switch( m_frameType )
86 {
89 default:
91
95
99 case FRAME_CVPCB:
102 }
103}
104
105
107{
108 m_backgroundColor = COLOR4D( 0.0, 0.0, 0.0, 1.0 );
109 m_ZoneDisplayMode = ZONE_DISPLAY_MODE::SHOW_FILLED;
110 m_netColorMode = NET_COLOR_MODE::RATSNEST;
111 m_ContrastModeDisplay = HIGH_CONTRAST_MODE::NORMAL;
112
113 m_trackOpacity = 1.0;
114 m_viaOpacity = 1.0;
115 m_padOpacity = 1.0;
116 m_zoneOpacity = 1.0;
117 m_imageOpacity = 1.0;
119
121
122 m_PadEditModePad = nullptr;
123
124 SetDashLengthRatio( 12 ); // From ISO 128-2
125 SetGapLengthRatio( 3 ); // From ISO 128-2
126
128
129 update();
130}
131
132
134{
136
137 // Init board layers colors:
138 for( int i = 0; i < PCB_LAYER_ID_COUNT; i++ )
139 {
140 m_layerColors[i] = aSettings->GetColor( i );
141
142 // Guard: if the alpha channel is too small, the layer is not visible.
143 if( m_layerColors[i].a < 0.2 )
144 m_layerColors[i].a = 0.2;
145 }
146
147 // Init specific graphic layers colors:
148 for( int i = GAL_LAYER_ID_START; i < GAL_LAYER_ID_END; i++ )
149 m_layerColors[i] = aSettings->GetColor( i );
150
151 // Colors for layers that aren't theme-able
154
155 // Netnames for copper layers
156 const COLOR4D lightLabel = aSettings->GetColor( NETNAMES_LAYER_ID_START );
157 const COLOR4D darkLabel = lightLabel.Inverted();
158
159 for( PCB_LAYER_ID layer : LSET::AllCuMask().CuStack() )
160 {
161 if( m_layerColors[layer].GetBrightness() > 0.5 )
162 m_layerColors[GetNetnameLayer( layer )] = darkLabel;
163 else
164 m_layerColors[GetNetnameLayer( layer )] = lightLabel;
165 }
166
167 if( PgmOrNull() ) // can be null if used without project (i.e. from python script)
169 else
170 m_hiContrastFactor = 1.0f - 0.8f; // default value
171
172 update();
173}
174
175
177{
178 m_hiContrastEnabled = aOptions.m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL;
182
184 m_viaOpacity = aOptions.m_ViaOpacity;
185 m_padOpacity = aOptions.m_PadOpacity;
186 m_zoneOpacity = aOptions.m_ZoneOpacity;
189}
190
191
192COLOR4D PCB_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const
193{
194 return GetColor( dynamic_cast<const BOARD_ITEM*>( aItem ), aLayer );
195}
196
197
198COLOR4D PCB_RENDER_SETTINGS::GetColor( const BOARD_ITEM* aItem, int aLayer ) const
199{
200 int netCode = -1;
201 int originalLayer = aLayer;
202
203 // Marker shadows
204 if( aLayer == LAYER_MARKER_SHADOWS )
205 return m_backgroundColor.WithAlpha( 0.6 );
206
207 // SMD pads use the copper netname layer
208 if( aLayer == LAYER_PAD_FR_NETNAMES )
209 aLayer = GetNetnameLayer( F_Cu );
210 else if( aLayer == LAYER_PAD_BK_NETNAMES )
211 aLayer = GetNetnameLayer( B_Cu );
212
213 if( IsHoleLayer( aLayer ) && m_isPrinting )
214 {
215 // Careful that we don't end up with the same colour for the annular ring and the hole
216 // when printing in B&W.
217 const PAD* pad = dynamic_cast<const PAD*>( aItem );
218 const PCB_VIA* via = dynamic_cast<const PCB_VIA*>( aItem );
219 int holeLayer = aLayer;
220 int annularRingLayer = UNDEFINED_LAYER;
221
222 // TODO(JE) padstacks -- this won't work, we don't know what the annular ring layer is
223 // Inserting F_Cu here for now.
224 if( pad && pad->GetAttribute() == PAD_ATTRIB::PTH )
225 annularRingLayer = F_Cu;
226 else if( via )
227 annularRingLayer = F_Cu;
228
229 if( annularRingLayer != UNDEFINED_LAYER
230 && m_layerColors[ holeLayer ] == m_layerColors[ annularRingLayer ] )
231 {
232 aLayer = LAYER_PCB_BACKGROUND;
233 }
234 }
235
236 // Zones should pull from the copper layer
237 if( aItem && aItem->Type() == PCB_ZONE_T )
238 {
239 if( IsZoneFillLayer( aLayer ) )
240 aLayer = aLayer - LAYER_ZONE_START;
241 }
242
243 // Hole walls should pull from the via hole layer since it does not vary with active copper
244 // layer. For simplicity of configuration, pad hole walls can use the via color.
245 else if( aLayer == LAYER_VIA_HOLEWALLS || aLayer == LAYER_PAD_HOLEWALLS )
246 aLayer = LAYER_VIA_HOLES;
247
248 // Show via mask layers if appropriate
249 if( aLayer == LAYER_VIA_THROUGH && !m_isPrinting )
250 {
251 if( aItem && aItem->GetBoard() )
252 {
253 LSET visibleLayers = aItem->GetBoard()->GetVisibleLayers()
254 & aItem->GetBoard()->GetEnabledLayers()
255 & aItem->GetLayerSet();
256
257 if( GetActiveLayer() == F_Mask && visibleLayers.test( F_Mask ) )
258 aLayer = F_Mask;
259 else if( GetActiveLayer() == B_Mask && visibleLayers.test( B_Mask ) )
260 aLayer = B_Mask;
261 else if( ( visibleLayers & LSET::AllCuMask() ).none() )
262 {
263 if( visibleLayers.any() )
264 aLayer = visibleLayers.Seq().back();
265 }
266 }
267 }
268
269 // Normal path: get the layer base color
270 COLOR4D color = m_layerColors[aLayer];
271
272 if( !aItem )
273 return m_layerColors[aLayer];
274
275 // Selection disambiguation
276 if( aItem->IsBrightened() )
277 return color.Brightened( m_selectFactor ).WithAlpha( 0.8 );
278
279 // Normal selection
280 if( aItem->IsSelected() )
281 color = m_layerColorsSel[aLayer];
282
283 // Some graphic objects are BOARD_CONNECTED_ITEM, but they are seen here as
284 // actually board connected objects only if on a copper layer
285 const BOARD_CONNECTED_ITEM* conItem =
286 aItem->IsConnected() && aItem->IsOnCopperLayer()
287 ? static_cast<const BOARD_CONNECTED_ITEM*>( aItem )
288 : nullptr;
289
290 // Try to obtain the netcode for the aItem
291 if( conItem )
292 netCode = conItem->GetNetCode();
293
294 bool highlighted = m_highlightEnabled && m_highlightNetcodes.count( netCode );
295 bool selected = aItem->IsSelected();
296
297 // Apply net color overrides
298 if( conItem && m_netColorMode == NET_COLOR_MODE::ALL && IsCopperLayer( aLayer ) )
299 {
300 COLOR4D netColor = COLOR4D::UNSPECIFIED;
301
302 auto ii = m_netColors.find( netCode );
303
304 if( ii != m_netColors.end() )
305 netColor = ii->second;
306
307 if( netColor == COLOR4D::UNSPECIFIED )
308 {
309 const NETCLASS* nc = conItem->GetEffectiveNetClass();
310
311 if( nc->HasPcbColor() )
312 netColor = nc->GetPcbColor();
313 }
314
315 if( netColor == COLOR4D::UNSPECIFIED )
316 netColor = color;
317
318 if( selected )
319 {
320 // Selection brightening overrides highlighting
321 netColor.Brighten( m_selectFactor );
322 }
323 else if( m_highlightEnabled )
324 {
325 // Highlight brightens objects on all layers and darkens everything else for contrast
326 if( highlighted )
327 netColor.Brighten( m_highlightFactor );
328 else
329 netColor.Darken( 1.0 - m_highlightFactor );
330 }
331
332 color = netColor;
333 }
334 else if( !selected && m_highlightEnabled )
335 {
336 // Single net highlight mode
337 color = m_highlightNetcodes.count( netCode ) ? m_layerColorsHi[aLayer]
338 : m_layerColorsDark[aLayer];
339 }
340
341 // Apply high-contrast dimming
342 if( m_hiContrastEnabled && m_highContrastLayers.size() && !highlighted && !selected )
343 {
345 bool isActive = m_highContrastLayers.count( aLayer );
346 bool hide = false;
347
348 switch( originalLayer )
349 {
350 // TODO(JE) not sure if this is needed
351 case LAYER_PADS:
352 {
353 const PAD* pad = static_cast<const PAD*>( aItem );
354
355 if( pad->IsOnLayer( primary ) && !pad->FlashLayer( primary ) )
356 {
357 isActive = false;
358
359 if( IsCopperLayer( primary ) )
360 hide = true;
361 }
362
364 isActive = false;
365
366 break;
367 }
368
369 case LAYER_VIA_BBLIND:
371 {
372 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
373
374 // Target graphic is active if the via crosses the primary layer
375 if( via->GetLayerSet().test( primary ) == 0 )
376 {
377 isActive = false;
378 hide = true;
379 }
380
381 break;
382 }
383
385 {
386 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
387
388 if( !via->FlashLayer( primary ) )
389 {
390 isActive = false;
391
392 if( IsCopperLayer( primary ) )
393 hide = true;
394 }
395
396 break;
397 }
398
402 // Pad holes are active is any physical layer is active
403 if( LSET::PhysicalLayersMask().test( primary ) == 0 )
404 isActive = false;
405
406 break;
407
408 case LAYER_VIA_HOLES:
410 {
411 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
412
413 if( via->GetViaType() == VIATYPE::THROUGH )
414 {
415 // A through via's hole is active if any physical layer is active
416 if( LSET::PhysicalLayersMask().test( primary ) == 0 )
417 isActive = false;
418 }
419 else
420 {
421 // A blind/buried or micro via's hole is active if it crosses the primary layer
422 if( via->GetLayerSet().test( primary ) == 0 )
423 isActive = false;
424 }
425
426 break;
427 }
428
429 case LAYER_DRC_ERROR:
432 isActive = true;
433 break;
434
435 default:
436 break;
437 }
438
439 if( !isActive )
440 {
441 // Graphics on Edge_Cuts layer are not fully dimmed or hidden because they are
442 // useful when working on another layer
443 // We could use a dim factor = m_hiContrastFactor, but to have a sufficient
444 // contrast whenever m_hiContrastFactor value, we clamp the factor to 0.3f
445 // (arbitray choice after tests)
446 float dim_factor_Edge_Cuts = std::max( m_hiContrastFactor, 0.3f );
447
448 if( m_ContrastModeDisplay == HIGH_CONTRAST_MODE::HIDDEN
449 || IsNetnameLayer( aLayer )
450 || hide )
451 {
452 if( originalLayer == Edge_Cuts )
453 color = color.Mix( m_layerColors[LAYER_PCB_BACKGROUND], dim_factor_Edge_Cuts );
454 else
456 }
457 else
458 {
459 if( originalLayer == Edge_Cuts )
460 color = color.Mix( m_layerColors[LAYER_PCB_BACKGROUND], dim_factor_Edge_Cuts );
461 else
463
464 // Reference images can't have their color mixed so just reduce the opacity a bit
465 // so they show through less
466 if( aItem->Type() == PCB_REFERENCE_IMAGE_T )
468 }
469 }
470 }
471 else if( originalLayer == LAYER_VIA_BBLIND || originalLayer == LAYER_VIA_MICROVIA )
472 {
473 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
474 const BOARD* board = via->GetBoard();
475 LSET visibleLayers = board->GetVisibleLayers() & board->GetEnabledLayers();
476
477 // Target graphic is visible if the via crosses a visible layer
478 if( ( via->GetLayerSet() & visibleLayers ).none() )
480 }
481
482 // Apply per-type opacity overrides
483 if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
485 else if( aItem->Type() == PCB_VIA_T )
486 color.a *= m_viaOpacity;
487 else if( aItem->Type() == PCB_PAD_T )
488 color.a *= m_padOpacity;
489 else if( aItem->Type() == PCB_ZONE_T && static_cast<const ZONE*>( aItem )->IsTeardropArea() )
491 else if( aItem->Type() == PCB_ZONE_T )
492 color.a *= m_zoneOpacity;
493 else if( aItem->Type() == PCB_REFERENCE_IMAGE_T )
495 else if( aItem->Type() == PCB_SHAPE_T && static_cast<const PCB_SHAPE*>( aItem )->IsFilled() )
497 else if( aItem->Type() == PCB_SHAPE_T && aItem->IsOnCopperLayer() )
499
500 if( aItem->GetForcedTransparency() > 0.0 )
501 color = color.WithAlpha( color.a * ( 1.0 - aItem->GetForcedTransparency() ) );
502
503 // No special modifiers enabled
504 return color;
505}
506
507
509{
510 return pcbconfig() && pcbconfig()->m_ShowPageLimits;
511}
512
513
515 PAINTER( aGal ),
516 m_frameType( aFrameType ),
517 m_maxError( ARC_HIGH_DEF ),
518 m_holePlatingThickness( 0 ),
519 m_lockedShadowMargin( 0 )
520{
521}
522
523
524int PCB_PAINTER::getLineThickness( int aActualThickness ) const
525{
526 // if items have 0 thickness, draw them with the outline
527 // width, otherwise respect the set value (which, no matter
528 // how small will produce something)
529 if( aActualThickness == 0 )
531
532 return aActualThickness;
533}
534
535
537{
538 return aPad->GetDrillShape();
539}
540
541
543{
544 SHAPE_SEGMENT segm = *aPad->GetEffectiveHoleShape().get();
545 return segm;
546}
547
548
549int PCB_PAINTER::getViaDrillSize( const PCB_VIA* aVia ) const
550{
551 return aVia->GetDrillValue();
552}
553
554
555bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
556{
557 if( !aItem->IsBOARD_ITEM() )
558 return false;
559
560 const BOARD_ITEM* item = static_cast<const BOARD_ITEM*>( aItem );
561
562 if( const BOARD* board = item->GetBoard() )
563 {
564 BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
568
569 if( item->GetParentFootprint() && !board->IsFootprintHolder() )
570 {
571 FOOTPRINT* parentFP = item->GetParentFootprint();
572
573 // Never draw footprint reference images on board
574 if( item->Type() == PCB_REFERENCE_IMAGE_T )
575 {
576 return false;
577 }
578 else if( item->GetLayerSet().count() > 1 )
579 {
580 // For multi-layer objects, exclude only those layers that are private
581 if( IsPcbLayer( aLayer ) && parentFP->GetPrivateLayers().test( aLayer ) )
582 return false;
583 }
584 else if( item->GetLayerSet().count() == 1 )
585 {
586 // For single-layer objects, exclude all layers including ancillary layers
587 // such as holes, netnames, etc.
588 PCB_LAYER_ID singleLayer = item->GetLayerSet().ExtractLayer();
589
590 if( parentFP->GetPrivateLayers().test( singleLayer ) )
591 return false;
592 }
593 }
594 }
595 else
596 {
599 }
600
601 // the "cast" applied in here clarifies which overloaded draw() is called
602 switch( item->Type() )
603 {
604 case PCB_TRACE_T:
605 draw( static_cast<const PCB_TRACK*>( item ), aLayer );
606 break;
607
608 case PCB_ARC_T:
609 draw( static_cast<const PCB_ARC*>( item ), aLayer );
610 break;
611
612 case PCB_VIA_T:
613 draw( static_cast<const PCB_VIA*>( item ), aLayer );
614 break;
615
616 case PCB_PAD_T:
617 draw( static_cast<const PAD*>( item ), aLayer );
618 break;
619
620 case PCB_SHAPE_T:
621 draw( static_cast<const PCB_SHAPE*>( item ), aLayer );
622 break;
623
625 draw( static_cast<const PCB_REFERENCE_IMAGE*>( item ), aLayer );
626 break;
627
628 case PCB_FIELD_T:
629 case PCB_TEXT_T:
630 draw( static_cast<const PCB_TEXT*>( item ), aLayer );
631 break;
632
633 case PCB_TEXTBOX_T:
634 draw( static_cast<const PCB_TEXTBOX*>( item ), aLayer );
635 break;
636
637 case PCB_TABLE_T:
638 draw( static_cast<const PCB_TABLE*>( item ), aLayer );
639 break;
640
641 case PCB_FOOTPRINT_T:
642 draw( static_cast<const FOOTPRINT*>( item ), aLayer );
643 break;
644
645 case PCB_GROUP_T:
646 draw( static_cast<const PCB_GROUP*>( item ), aLayer );
647 break;
648
649 case PCB_ZONE_T:
650 draw( static_cast<const ZONE*>( item ), aLayer );
651 break;
652
654 case PCB_DIM_CENTER_T:
655 case PCB_DIM_RADIAL_T:
657 case PCB_DIM_LEADER_T:
658 draw( static_cast<const PCB_DIMENSION_BASE*>( item ), aLayer );
659 break;
660
661 case PCB_TARGET_T:
662 draw( static_cast<const PCB_TARGET*>( item ) );
663 break;
664
665 case PCB_MARKER_T:
666 draw( static_cast<const PCB_MARKER*>( item ), aLayer );
667 break;
668
669 default:
670 // Painter does not know how to draw the object
671 return false;
672 }
673
674 // Draw bounding boxes after drawing objects so they can be seen.
676 {
677 // Show bounding boxes of painted objects for debugging.
678 BOX2I box = item->GetBoundingBox();
679
680 m_gal->SetIsFill( false );
681 m_gal->SetIsStroke( true );
682
683 if( item->Type() == PCB_FOOTPRINT_T )
684 {
685 m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
686 COLOR4D( MAGENTA ) );
687 }
688 else
689 {
690 m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
691 COLOR4D( 0.4, 0.4, 0.4, 1 ) );
692 }
693
694 m_gal->SetLineWidth( 1 );
695 m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
696
697 if( item->Type() == PCB_FOOTPRINT_T )
698 {
699 m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
700 COLOR4D( CYAN ) );
701
702 const FOOTPRINT* fp = static_cast<const FOOTPRINT*>( item );
703
704 if( fp )
705 {
706 const SHAPE_POLY_SET& convex = fp->GetBoundingHull();
707
708 m_gal->DrawPolyline( convex.COutline( 0 ) );
709 }
710 }
711 }
712
713 return true;
714}
715
716
717void PCB_PAINTER::draw( const PCB_TRACK* aTrack, int aLayer )
718{
719 VECTOR2I start( aTrack->GetStart() );
720 VECTOR2I end( aTrack->GetEnd() );
721 int track_width = aTrack->GetWidth();
722 COLOR4D color = m_pcbSettings.GetColor( aTrack, aLayer );
723
724 if( IsNetnameLayer( aLayer ) )
725 {
726 if( !pcbconfig() || pcbconfig()->m_Display.m_NetNames < 2 )
727 return;
728
729 if( aTrack->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
730 return;
731
732 SHAPE_SEGMENT trackShape( { aTrack->GetStart(), aTrack->GetEnd() }, aTrack->GetWidth() );
733 renderNetNameForSegment( trackShape, color, aTrack->GetDisplayNetname() );
734 return;
735 }
736 else if( IsCopperLayer( aLayer ) || IsSolderMaskLayer( aLayer )
737 || aLayer == LAYER_LOCKED_ITEM_SHADOW )
738 {
739 // Draw a regular track
740 bool outline_mode = pcbconfig()
742 && aLayer != LAYER_LOCKED_ITEM_SHADOW;
745 m_gal->SetIsStroke( outline_mode );
746 m_gal->SetIsFill( not outline_mode );
748
749 if( IsSolderMaskLayer( aLayer ) )
750 track_width = track_width + aTrack->GetSolderMaskExpansion() * 2;
751
752 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
753 track_width = track_width + m_lockedShadowMargin;
754
755 m_gal->DrawSegment( start, end, track_width );
756 }
757
758 // Clearance lines
759 if( pcbconfig() && pcbconfig()->m_Display.m_TrackClearance == SHOW_WITH_VIA_ALWAYS
761 && aLayer != LAYER_LOCKED_ITEM_SHADOW )
762 {
763 /*
764 * Showing the clearance area is not obvious for optionally-flashed pads and vias, so we
765 * choose to not display clearance lines at all on non-copper active layers. We follow
766 * the same rule for tracks to be consistent (even though they don't have the same issue).
767 */
769 const BOARD* board = aTrack->GetBoard();
770
771 if( IsCopperLayer( activeLayer ) && board->GetVisibleLayers().test( activeLayer ) )
772 {
773 int clearance = aTrack->GetOwnClearance( activeLayer );
774
776 m_gal->SetIsFill( false );
777 m_gal->SetIsStroke( true );
779 m_gal->DrawSegment( start, end, track_width + clearance * 2 );
780 }
781 }
782}
783
784
786 const wxString& aNetName ) const
787{
788 // When drawing netnames, clip the track to the viewport
789 BOX2D viewport;
790 VECTOR2D screenSize = m_gal->GetScreenPixelSize();
791 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
792
793 viewport.SetOrigin( VECTOR2D( matrix * VECTOR2D( 0, 0 ) ) );
794 viewport.SetEnd( VECTOR2D( matrix * screenSize ) );
795 viewport.Normalize();
796
797 int num_char = aNetName.size();
798
799 // Check if the track is long enough to have a netname displayed
800 int seg_minlength = aSeg.GetWidth() * num_char;
801 SEG::ecoord seg_minlength_sq = (SEG::ecoord)seg_minlength * seg_minlength;
802
803 if( aSeg.GetSeg().SquaredLength() < seg_minlength_sq )
804 return;
805
806 double textSize = aSeg.GetWidth();
807 double penWidth = textSize / 12.0;
808 EDA_ANGLE textOrientation;
809 int num_names = 1;
810
811 VECTOR2I start = aSeg.GetSeg().A;
812 VECTOR2I end = aSeg.GetSeg().B;
813 VECTOR2D segV = end - start;
814
815 if( end.y == start.y ) // horizontal
816 {
817 textOrientation = ANGLE_HORIZONTAL;
818 num_names = std::max( num_names, KiROUND( aSeg.GetSeg().Length() / viewport.GetWidth() ) );
819 }
820 else if( end.x == start.x ) // vertical
821 {
822 textOrientation = ANGLE_VERTICAL;
823 num_names = std::max( num_names, KiROUND( aSeg.GetSeg().Length() / viewport.GetHeight() ) );
824 }
825 else
826 {
827 textOrientation = -EDA_ANGLE( segV );
828 textOrientation.Normalize90();
829
830 double min_size = std::min( viewport.GetWidth(), viewport.GetHeight() );
831 num_names = std::max( num_names, KiROUND( aSeg.GetSeg().Length() / ( M_SQRT2 * min_size ) ) );
832 }
833
834 m_gal->SetIsStroke( true );
835 m_gal->SetIsFill( false );
836 m_gal->SetStrokeColor( aColor );
837 m_gal->SetLineWidth( penWidth );
838 m_gal->SetFontBold( false );
839 m_gal->SetFontItalic( false );
840 m_gal->SetFontUnderlined( false );
841 m_gal->SetTextMirrored( false );
842 m_gal->SetGlyphSize( VECTOR2D( textSize * 0.55, textSize * 0.55 ) );
845
846 int divisions = num_names + 1;
847
848 for( int ii = 1; ii < divisions; ++ii )
849 {
850 VECTOR2I textPosition = start + segV * ( (double) ii / divisions );
851
852 if( viewport.Contains( textPosition ) )
853 m_gal->BitmapText( aNetName, textPosition, textOrientation );
854 }
855}
856
857
858void PCB_PAINTER::draw( const PCB_ARC* aArc, int aLayer )
859{
860 VECTOR2D center( aArc->GetCenter() );
861 int width = aArc->GetWidth();
862 COLOR4D color = m_pcbSettings.GetColor( aArc, aLayer );
863 double radius = aArc->GetRadius();
864 EDA_ANGLE start_angle = aArc->GetArcAngleStart();
865 EDA_ANGLE angle = aArc->GetAngle();
866
867 if( IsNetnameLayer( aLayer ) )
868 {
869 // Ummm, yeah. Anyone fancy implementing text on a path?
870 return;
871 }
872 else if( IsCopperLayer( aLayer ) || IsSolderMaskLayer( aLayer )
873 || aLayer == LAYER_LOCKED_ITEM_SHADOW )
874 {
875 // Draw a regular track
876 bool outline_mode = pcbconfig()
878 && aLayer != LAYER_LOCKED_ITEM_SHADOW;
881 m_gal->SetIsStroke( outline_mode );
882 m_gal->SetIsFill( not outline_mode );
884
885 if( IsSolderMaskLayer( aLayer ) )
886 width = width + aArc->GetSolderMaskExpansion() * 2;
887
888 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
889 width = width + m_lockedShadowMargin;
890
891 m_gal->DrawArcSegment( center, radius, start_angle, angle, width, m_maxError );
892 }
893
894 // Clearance lines
895 if( pcbconfig() && pcbconfig()->m_Display.m_TrackClearance == SHOW_WITH_VIA_ALWAYS
897 && aLayer != LAYER_LOCKED_ITEM_SHADOW )
898 {
899 /*
900 * Showing the clearance area is not obvious for optionally-flashed pads and vias, so we
901 * choose to not display clearance lines at all on non-copper active layers. We follow
902 * the same rule for tracks to be consistent (even though they don't have the same issue).
903 */
905 const BOARD* board = aArc->GetBoard();
906
907 if( IsCopperLayer( activeLayer ) && board->GetVisibleLayers().test( activeLayer ) )
908 {
909 int clearance = aArc->GetOwnClearance( activeLayer );
910
912 m_gal->SetIsFill( false );
913 m_gal->SetIsStroke( true );
915
916 m_gal->DrawArcSegment( center, radius, start_angle, angle, width + clearance * 2,
917 m_maxError );
918 }
919 }
920
921// Debug only: enable this code only to test the TransformArcToPolygon function
922// and display the polygon outline created by it.
923// arcs on F_Cu are approximated with ERROR_INSIDE, others with ERROR_OUTSIDE
924#if 0
925 SHAPE_POLY_SET cornerBuffer;
926 ERROR_LOC errorloc = aLayer == F_Cu ? ERROR_LOC::ERROR_INSIDE : ERROR_LOC::ERROR_OUTSIDE;
927 TransformArcToPolygon( cornerBuffer, aArc->GetStart(), aArc->GetMid(), aArc->GetEnd(), width,
928 m_maxError, errorloc );
930 m_gal->SetIsFill( false );
931 m_gal->SetIsStroke( true );
932 m_gal->SetStrokeColor( COLOR4D( 0, 0, 1.0, 1.0 ) );
933 m_gal->DrawPolygon( cornerBuffer );
934#endif
935
936// Debug only: enable this code only to test the SHAPE_ARC::ConvertToPolyline function
937// and display the polyline created by it.
938#if 0
939 SHAPE_ARC arc( aArc->GetCenter(), aArc->GetStart(), aArc->GetAngle(), aArc->GetWidth() );
942 m_gal->SetIsFill( false );
943 m_gal->SetIsStroke( true );
944 m_gal->SetStrokeColor( COLOR4D( 0.3, 0.2, 0.5, 1.0 ) );
945
946 for( int idx = 1; idx < arcSpine.PointCount(); idx++ )
947 m_gal->DrawSegment( arcSpine.CPoint( idx-1 ), arcSpine.CPoint( idx ), aArc->GetWidth() );
948#endif
949}
950
951
952void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
953{
954 const BOARD* board = aVia->GetBoard();
955 COLOR4D color = m_pcbSettings.GetColor( aVia, aLayer );
956 VECTOR2D center( aVia->GetStart() );
957
958 if( color == COLOR4D::CLEAR )
959 return;
960
961 PCB_LAYER_ID currentLayer = ToLAYER_ID( aLayer );
962 PCB_LAYER_ID layerTop, layerBottom;
963 aVia->LayerPair( &layerTop, &layerBottom );
964
965 // Blind/buried vias (and microvias) will use different hole and label rendering
966 bool isBlindBuried = aVia->GetViaType() == VIATYPE::BLIND_BURIED
967 || ( aVia->GetViaType() == VIATYPE::MICROVIA
968 && ( layerTop != F_Cu || layerBottom != B_Cu ) );
969
970 // Draw description layer
971 if( IsNetnameLayer( aLayer ) )
972 {
973 VECTOR2D position( center );
974
975 // Is anything that we can display enabled (netname and/or layers ids)?
976 bool showNets = pcbconfig() && pcbconfig()->m_Display.m_NetNames != 0
977 && !aVia->GetNetname().empty();
978 bool showLayers = aVia->GetViaType() != VIATYPE::THROUGH;
979
980 if( !showNets && !showLayers )
981 return;
982
983 double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
984 double size = aVia->GetWidth( currentLayer );
985
986 // Font size limits
987 if( size > maxSize )
988 size = maxSize;
989
990 m_gal->Save();
991 m_gal->Translate( position );
992
993 // Default font settings
997 m_gal->SetFontBold( false );
998 m_gal->SetFontItalic( false );
999 m_gal->SetFontUnderlined( false );
1000 m_gal->SetTextMirrored( false );
1001 m_gal->SetStrokeColor( m_pcbSettings.GetColor( aVia, aLayer ) );
1002 m_gal->SetIsStroke( true );
1003 m_gal->SetIsFill( false );
1004
1005 // Set the text position via position. if only one text, it is on the via position
1006 // For 2 lines, the netname is slightly below the center, and the layer IDs above
1007 // the netname
1008 VECTOR2D textpos( 0.0, 0.0 );
1009
1010 wxString netname = aVia->GetDisplayNetname();
1011
1012 PCB_LAYER_ID topLayerId = aVia->TopLayer();
1013 PCB_LAYER_ID bottomLayerId = aVia->BottomLayer();
1014 int topLayer; // The via top layer number (from 1 to copper layer count)
1015 int bottomLayer; // The via bottom layer number (from 1 to copper layer count)
1016
1017 switch( topLayerId )
1018 {
1019 case F_Cu: topLayer = 1; break;
1020 case B_Cu: topLayer = board->GetCopperLayerCount(); break;
1021 default: topLayer = (topLayerId - B_Cu)/2 + 1; break;
1022 }
1023
1024 switch( bottomLayerId )
1025 {
1026 case F_Cu: bottomLayer = 1; break;
1027 case B_Cu: bottomLayer = board->GetCopperLayerCount(); break;
1028 default: bottomLayer = (bottomLayerId - B_Cu)/2 + 1; break;
1029 }
1030
1031 wxString layerIds;
1032#if wxUSE_UNICODE_WCHAR
1033 layerIds << std::to_wstring( topLayer ) << L'-' << std::to_wstring( bottomLayer );
1034#else
1035 layerIds << std::to_string( topLayer ) << '-' << std::to_string( bottomLayer );
1036#endif
1037
1038 // a good size is set room for at least 6 chars, to be able to print 2 lines of text,
1039 // or at least 3 chars for only the netname
1040 // (The layerIds string has 5 chars max)
1041 int minCharCnt = showLayers ? 6 : 3;
1042
1043 // approximate the size of netname and layerIds text:
1044 double tsize = 1.5 * size / std::max( PrintableCharCount( netname ), minCharCnt );
1045 tsize = std::min( tsize, size );
1046
1047 // Use a smaller text size to handle interline, pen size..
1048 tsize *= 0.75;
1049 VECTOR2D namesize( tsize, tsize );
1050
1051 // For 2 lines, adjust the text pos (move it a small amount to the bottom)
1052 if( showLayers && showNets )
1053 textpos.y += ( tsize * 1.3 )/ 2;
1054
1055 m_gal->SetGlyphSize( namesize );
1056 m_gal->SetLineWidth( namesize.x / 10.0 );
1057
1058 if( showNets )
1059 m_gal->BitmapText( netname, textpos, ANGLE_HORIZONTAL );
1060
1061 if( showLayers )
1062 {
1063 if( showNets )
1064 textpos.y -= tsize * 1.3;
1065
1066 m_gal->BitmapText( layerIds, textpos, ANGLE_HORIZONTAL );
1067 }
1068
1069 m_gal->Restore();
1070
1071 return;
1072 }
1073
1074 bool outline_mode = pcbconfig() && !pcbconfig()->m_Display.m_DisplayViaFill;
1075
1078 m_gal->SetIsStroke( true );
1079 m_gal->SetIsFill( false );
1080
1081 if( outline_mode )
1083
1084 if( aLayer == LAYER_VIA_HOLEWALLS )
1085 {
1086 double radius = ( getViaDrillSize( aVia ) / 2.0 ) + m_holePlatingThickness;
1087
1088 if( !outline_mode )
1089 {
1091 radius -= m_holePlatingThickness / 2.0;
1092 }
1093
1094 // Underpaint the hole so that there aren't artifacts at its edge
1095 m_gal->SetIsFill( true );
1096
1097 m_gal->DrawCircle( center, radius );
1098 }
1099 else if( aLayer == LAYER_VIA_HOLES )
1100 {
1101 double radius = getViaDrillSize( aVia ) / 2.0;
1102
1103 m_gal->SetIsStroke( false );
1104 m_gal->SetIsFill( true );
1105
1106 if( isBlindBuried && !m_pcbSettings.IsPrinting() )
1107 {
1108 m_gal->SetIsStroke( false );
1109 m_gal->SetIsFill( true );
1110
1111 m_gal->SetFillColor( m_pcbSettings.GetColor( aVia, layerTop ) );
1112 m_gal->DrawArc( center, radius, EDA_ANGLE( 180, DEGREES_T ),
1113 EDA_ANGLE( 180, DEGREES_T ) );
1114
1115 m_gal->SetFillColor( m_pcbSettings.GetColor( aVia, layerBottom ) );
1116 m_gal->DrawArc( center, radius, EDA_ANGLE( 0, DEGREES_T ),
1117 EDA_ANGLE( 180, DEGREES_T ) );
1118 }
1119 else
1120 {
1121 m_gal->DrawCircle( center, radius );
1122 }
1123 }
1124 else if( ( aLayer == F_Mask && aVia->IsOnLayer( F_Mask ) )
1125 || ( aLayer == B_Mask && aVia->IsOnLayer( B_Mask ) ) )
1126 {
1127 int margin = board->GetDesignSettings().m_SolderMaskExpansion;
1128
1129 m_gal->SetIsFill( true );
1130 m_gal->SetIsStroke( false );
1131
1132 m_gal->SetLineWidth( margin );
1133 m_gal->DrawCircle( center, aVia->GetWidth( currentLayer ) / 2.0 + margin );
1134 }
1135 else if( m_pcbSettings.IsPrinting() || IsCopperLayer( aLayer ) )
1136 {
1137 int annular_width = ( aVia->GetWidth( currentLayer ) - getViaDrillSize( aVia ) ) / 2.0;
1138 double radius = aVia->GetWidth( currentLayer ) / 2.0;
1139 bool draw = false;
1140
1142 {
1144 }
1145 else if( aVia->IsSelected() )
1146 {
1147 draw = true;
1148 }
1149 else if( aVia->FlashLayer( board->GetVisibleLayers() & board->GetEnabledLayers() ) )
1150 {
1151 draw = true;
1152 }
1153
1154 if( !aVia->FlashLayer( aLayer ) )
1155 draw = false;
1156
1157 if( !outline_mode )
1158 {
1159 m_gal->SetLineWidth( annular_width );
1160 radius -= annular_width / 2.0;
1161 }
1162
1163 if( draw )
1164 m_gal->DrawCircle( center, radius );
1165 }
1166 else if( aLayer == LAYER_LOCKED_ITEM_SHADOW ) // draw a ring around the via
1167 {
1169
1170 m_gal->DrawCircle( center,
1171 ( aVia->GetWidth( currentLayer ) + m_lockedShadowMargin ) / 2.0 );
1172 }
1173
1174 // Clearance lines
1176 && aLayer != LAYER_VIA_HOLES
1178 && aLayer != LAYER_LOCKED_ITEM_SHADOW )
1179 {
1180 /*
1181 * Showing the clearance area is not obvious as the clearance extends from the via's pad
1182 * on flashed copper layers and from the via's hole on non-flashed copper layers. Because
1183 * of this, we choose to not display clearance lines at all on non-copper active layers as
1184 * it's not clear which we'd be displaying.
1185 */
1187
1188 if( IsCopperLayer( activeLayer ) && board->GetVisibleLayers().test( activeLayer ) )
1189 {
1190 double radius;
1191
1192 if( aVia->FlashLayer( activeLayer ) )
1193 radius = aVia->GetWidth( activeLayer ) / 2.0;
1194 else
1195 radius = getViaDrillSize( aVia ) / 2.0 + m_holePlatingThickness;
1196
1198 m_gal->SetIsFill( false );
1199 m_gal->SetIsStroke( true );
1201 m_gal->DrawCircle( center, radius + aVia->GetOwnClearance( activeLayer ) );
1202 }
1203 }
1204}
1205
1206
1207void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
1208{
1209 const BOARD* board = aPad->GetBoard();
1210 COLOR4D color = m_pcbSettings.GetColor( aPad, aLayer );
1211 const PCB_LAYER_ID& pcbLayer = static_cast<PCB_LAYER_ID>( aLayer );
1212
1213 if( IsNetnameLayer( aLayer ) )
1214 {
1215 PCBNEW_SETTINGS::DISPLAY_OPTIONS* displayOpts = pcbconfig() ? &pcbconfig()->m_Display : nullptr;
1216 wxString netname;
1217 wxString padNumber;
1218
1219 if( viewer_settings()->m_ViewersDisplay.m_DisplayPadNumbers )
1220 {
1221 padNumber = UnescapeString( aPad->GetNumber() );
1222
1223 if( dynamic_cast<CVPCB_SETTINGS*>( viewer_settings() ) )
1224 netname = aPad->GetPinFunction();
1225 }
1226
1227 if( displayOpts && !dynamic_cast<CVPCB_SETTINGS*>( viewer_settings() ) )
1228 {
1229 if( displayOpts->m_NetNames == 1 || displayOpts->m_NetNames == 3 )
1230 netname = aPad->GetDisplayNetname();
1231
1232 if( aPad->IsNoConnectPad() )
1233 netname = wxT( "x" );
1234 else if( aPad->IsFreePad() )
1235 netname = wxT( "*" );
1236 }
1237
1238 if( netname.IsEmpty() && padNumber.IsEmpty() )
1239 return;
1240
1241 BOX2I padBBox = aPad->GetBoundingBox();
1242 VECTOR2D position = padBBox.Centre();
1243 VECTOR2D padsize = VECTOR2D( padBBox.GetSize() );
1244
1245 if( aPad->IsEntered() )
1246 {
1247 FOOTPRINT* fp = aPad->GetParentFootprint();
1248
1249 // Find the number box
1250 for( const BOARD_ITEM* aItem : fp->GraphicalItems() )
1251 {
1252 if( aItem->Type() == PCB_SHAPE_T )
1253 {
1254 const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
1255
1256 if( shape->IsProxyItem() && shape->GetShape() == SHAPE_T::RECTANGLE )
1257 {
1258 position = shape->GetCenter();
1259 padsize = shape->GetBotRight() - shape->GetTopLeft();
1260
1261 // We normally draw a bit outside the pad, but this will be somewhat
1262 // unexpected when the user has drawn a box.
1263 padsize *= 0.9;
1264
1265 break;
1266 }
1267 }
1268 }
1269 }
1270 else if( aPad->GetShape( pcbLayer ) == PAD_SHAPE::CUSTOM )
1271 {
1272 // See if we have a number box
1273 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( pcbLayer ) )
1274 {
1275 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::RECTANGLE )
1276 {
1277 position = primitive->GetCenter();
1278 RotatePoint( position, aPad->GetOrientation() );
1279 position += aPad->ShapePos( pcbLayer );
1280
1281 padsize.x = abs( primitive->GetBotRight().x - primitive->GetTopLeft().x );
1282 padsize.y = abs( primitive->GetBotRight().y - primitive->GetTopLeft().y );
1283
1284 // We normally draw a bit outside the pad, but this will be somewhat
1285 // unexpected when the user has drawn a box.
1286 padsize *= 0.9;
1287
1288 break;
1289 }
1290 }
1291 }
1292
1293 if( aPad->GetShape( pcbLayer ) != PAD_SHAPE::CUSTOM )
1294 {
1295 // Don't allow a 45° rotation to bloat a pad's bounding box unnecessarily
1296 double limit = std::min( aPad->GetSize( pcbLayer ).x,
1297 aPad->GetSize( pcbLayer ).y ) * 1.1;
1298
1299 if( padsize.x > limit && padsize.y > limit )
1300 {
1301 padsize.x = limit;
1302 padsize.y = limit;
1303 }
1304 }
1305
1306 double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
1307 double size = padsize.y;
1308
1309 m_gal->Save();
1310 m_gal->Translate( position );
1311
1312 // Keep the size ratio for the font, but make it smaller
1313 if( padsize.x < ( padsize.y * 0.95 ) )
1314 {
1316 size = padsize.x;
1317 std::swap( padsize.x, padsize.y );
1318 }
1319
1320 // Font size limits
1321 if( size > maxSize )
1322 size = maxSize;
1323
1324 // Default font settings
1328 m_gal->SetFontBold( false );
1329 m_gal->SetFontItalic( false );
1330 m_gal->SetFontUnderlined( false );
1331 m_gal->SetTextMirrored( false );
1332 m_gal->SetStrokeColor( m_pcbSettings.GetColor( aPad, aLayer ) );
1333 m_gal->SetIsStroke( true );
1334 m_gal->SetIsFill( false );
1335
1336 // We have already translated the GAL to be centered at the center of the pad's
1337 // bounding box
1338 VECTOR2I textpos( 0, 0 );
1339
1340 // Divide the space, to display both pad numbers and netnames and set the Y text
1341 // offset position to display 2 lines
1342 int Y_offset_numpad = 0;
1343 int Y_offset_netname = 0;
1344
1345 if( !netname.IsEmpty() && !padNumber.IsEmpty() )
1346 {
1347 // The magic numbers are defined experimentally for a better look.
1348 size = size / 2.5;
1349 Y_offset_netname = size / 1.4; // netname size is usually smaller than num pad
1350 // so the offset can be smaller
1351 Y_offset_numpad = size / 1.7;
1352 }
1353
1354 // We are using different fonts to display names, depending on the graphic
1355 // engine (OpenGL or Cairo).
1356 // Xscale_for_stroked_font adjust the text X size for cairo (stroke fonts) engine
1357 const double Xscale_for_stroked_font = 0.9;
1358
1359 if( !netname.IsEmpty() )
1360 {
1361 // approximate the size of net name text:
1362 // We use a size for at least 5 chars, to give a good look even for short names
1363 // (like VCC, GND...)
1364 double tsize = 1.5 * padsize.x / std::max( PrintableCharCount( netname )+1, 5 );
1365 tsize = std::min( tsize, size );
1366
1367 // Use a smaller text size to handle interline, pen size...
1368 tsize *= 0.85;
1369
1370 // Round and oval pads have less room to display the net name than other
1371 // (i.e RECT) shapes, so reduce the text size for these shapes
1372 if( aPad->GetShape( pcbLayer ) == PAD_SHAPE::CIRCLE
1373 || aPad->GetShape( pcbLayer ) == PAD_SHAPE::OVAL )
1374 {
1375 tsize *= 0.9;
1376 }
1377
1378 VECTOR2D namesize( tsize*Xscale_for_stroked_font, tsize );
1379 textpos.y = std::min( tsize * 1.4, double( Y_offset_netname ) );
1380
1381 m_gal->SetGlyphSize( namesize );
1382 m_gal->SetLineWidth( namesize.x / 6.0 );
1383 m_gal->SetFontBold( true );
1384 m_gal->BitmapText( netname, textpos, ANGLE_HORIZONTAL );
1385 }
1386
1387 if( !padNumber.IsEmpty() )
1388 {
1389 // approximate the size of the pad number text:
1390 // We use a size for at least 3 chars, to give a good look even for short numbers
1391 double tsize = 1.5 * padsize.x / std::max( PrintableCharCount( padNumber ), 3 );
1392 tsize = std::min( tsize, size );
1393
1394 // Use a smaller text size to handle interline, pen size...
1395 tsize *= 0.85;
1396 tsize = std::min( tsize, size );
1397 VECTOR2D numsize( tsize*Xscale_for_stroked_font, tsize );
1398 textpos.y = -Y_offset_numpad;
1399
1400 m_gal->SetGlyphSize( numsize );
1401 m_gal->SetLineWidth( numsize.x / 6.0 );
1402 m_gal->SetFontBold( true );
1403 m_gal->BitmapText( padNumber, textpos, ANGLE_HORIZONTAL );
1404 }
1405
1406 m_gal->Restore();
1407
1408 return;
1409 }
1410 else if( aLayer == LAYER_PAD_HOLEWALLS )
1411 {
1412 m_gal->SetIsFill( false );
1413 m_gal->SetIsStroke( true );
1416
1417 std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
1418 int holeSize = slot->GetWidth() + m_holePlatingThickness;
1419
1420 if( slot->GetSeg().A == slot->GetSeg().B ) // Circular hole
1421 m_gal->DrawCircle( slot->GetSeg().A, KiROUND( holeSize / 2.0 ) );
1422 else
1423 m_gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B, holeSize );
1424
1425 return;
1426 }
1427
1428 bool outline_mode = !viewer_settings()->m_ViewersDisplay.m_DisplayPadFill;
1429
1431 outline_mode = true;
1432
1433 if( outline_mode )
1434 {
1435 // Outline mode
1436 m_gal->SetIsFill( false );
1437 m_gal->SetIsStroke( true );
1440 }
1441 else
1442 {
1443 // Filled mode
1444 m_gal->SetIsFill( true );
1445 m_gal->SetIsStroke( false );
1447 }
1448
1449 bool drawShape = false;
1450
1451 if( aLayer == LAYER_PAD_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
1452 {
1453 SHAPE_SEGMENT slot = getPadHoleShape( aPad );
1454
1455 if( slot.GetSeg().A == slot.GetSeg().B ) // Circular hole
1456 m_gal->DrawCircle( slot.GetSeg().A, slot.GetWidth() / 2.0 );
1457 else
1458 m_gal->DrawSegment( slot.GetSeg().A, slot.GetSeg().B, slot.GetWidth() );
1459 }
1460 else if( m_pcbSettings.IsPrinting() )
1461 {
1462 drawShape = aPad->FlashLayer( m_pcbSettings.GetPrintLayers() );
1463 }
1464 else if( aPad->FlashLayer( board->GetVisibleLayers() & board->GetEnabledLayers() ) )
1465 {
1466 drawShape = true;
1467 }
1468 else if( aPad->IsSelected() )
1469 {
1470 drawShape = true;
1471 outline_mode = true;
1472 }
1473
1474 if( outline_mode )
1475 {
1476 // Outline mode
1477 m_gal->SetIsFill( false );
1478 m_gal->SetIsStroke( true );
1481 }
1482
1483 if( drawShape )
1484 {
1485 VECTOR2I pad_size = aPad->GetSize( pcbLayer );
1486 VECTOR2I margin;
1487
1488 switch( aLayer )
1489 {
1490 case F_Mask:
1491 case B_Mask:
1492 margin.x = margin.y = aPad->GetSolderMaskExpansion( pcbLayer );
1493 break;
1494
1495 case F_Paste:
1496 case B_Paste:
1497 margin = aPad->GetSolderPasteMargin( pcbLayer );
1498 break;
1499
1500 default:
1501 margin.x = margin.y = 0;
1502 break;
1503 }
1504
1505 std::unique_ptr<PAD> dummyPad;
1506 std::shared_ptr<SHAPE_COMPOUND> shapes;
1507
1508 // Drawing components of compound shapes in outline mode produces a mess.
1509 bool simpleShapes = !outline_mode;
1510
1511 if( simpleShapes )
1512 {
1513 if( ( margin.x != margin.y && aPad->GetShape( pcbLayer ) != PAD_SHAPE::CUSTOM )
1514 || ( aPad->GetShape( pcbLayer ) == PAD_SHAPE::ROUNDRECT
1515 && ( margin.x < 0 || margin.y < 0 ) ) )
1516 {
1517 // Our algorithms below (polygon inflation in particular) can't handle differential
1518 // inflation along separate axes. So for those cases we build a dummy pad instead,
1519 // and inflate it.
1520
1521 // Margin is added to both sides. If the total margin is larger than the pad
1522 // then don't display this layer
1523 if( pad_size.x + 2 * margin.x <= 0 || pad_size.y + 2 * margin.y <= 0 )
1524 return;
1525
1526 dummyPad.reset( static_cast<PAD*>( aPad->Duplicate() ) );
1527
1528 if( dummyPad->GetParentGroup() )
1529 dummyPad->GetParentGroup()->RemoveItem( dummyPad.get() );
1530
1531 int initial_radius = dummyPad->GetRoundRectCornerRadius( pcbLayer );
1532
1533 dummyPad->SetSize( pcbLayer, pad_size + margin + margin );
1534
1535 if( dummyPad->GetShape( pcbLayer ) == PAD_SHAPE::ROUNDRECT )
1536 {
1537 // To keep the right margin around the corners, we need to modify the corner radius.
1538 // We must have only one radius correction, so use the smallest absolute margin.
1539 int radius_margin = std::max( margin.x, margin.y ); // radius_margin is < 0
1540 dummyPad->SetRoundRectCornerRadius(
1541 pcbLayer, std::max( initial_radius + radius_margin, 0 ) );
1542 }
1543
1544 shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>(
1545 dummyPad->GetEffectiveShape( pcbLayer ) );
1546 margin.x = margin.y = 0;
1547 }
1548 else
1549 {
1550 shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>(
1551 aPad->GetEffectiveShape( pcbLayer ) );
1552 }
1553
1554 // The dynamic cast above will fail if the pad returned the hole shape or a null shape
1555 // instead of a SHAPE_COMPOUND, which happens if we're on a copper layer and the pad has
1556 // no shape on that layer.
1557 if( !shapes )
1558 return;
1559
1560 if( aPad->GetShape( pcbLayer ) == PAD_SHAPE::CUSTOM && ( margin.x || margin.y ) )
1561 {
1562 // We can't draw as shapes because we don't know which edges are internal and which
1563 // are external (so we don't know when to apply the margin and when not to).
1564 simpleShapes = false;
1565 }
1566
1567 for( const SHAPE* shape : shapes->Shapes() )
1568 {
1569 if( !simpleShapes )
1570 break;
1571
1572 switch( shape->Type() )
1573 {
1574 case SH_SEGMENT:
1575 case SH_CIRCLE:
1576 case SH_RECT:
1577 case SH_SIMPLE:
1578 // OK so far
1579 break;
1580
1581 default:
1582 // Not OK
1583 simpleShapes = false;
1584 break;
1585 }
1586 }
1587 }
1588
1589 if( simpleShapes )
1590 {
1591 for( const SHAPE* shape : shapes->Shapes() )
1592 {
1593 switch( shape->Type() )
1594 {
1595 case SH_SEGMENT:
1596 {
1597 const SHAPE_SEGMENT* seg = (const SHAPE_SEGMENT*) shape;
1598 int effectiveWidth = seg->GetWidth() + 2 * margin.x;
1599
1600 if( effectiveWidth > 0 )
1601 m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, effectiveWidth );
1602
1603 break;
1604 }
1605
1606 case SH_CIRCLE:
1607 {
1608 const SHAPE_CIRCLE* circle = (const SHAPE_CIRCLE*) shape;
1609 int effectiveRadius = circle->GetRadius() + margin.x;
1610
1611 if( effectiveRadius > 0 )
1612 m_gal->DrawCircle( circle->GetCenter(), effectiveRadius );
1613
1614 break;
1615 }
1616
1617 case SH_RECT:
1618 {
1619 const SHAPE_RECT* r = (const SHAPE_RECT*) shape;
1620 VECTOR2I pos = r->GetPosition();
1621 VECTOR2I effectiveMargin = margin;
1622
1623 if( effectiveMargin.x < 0 )
1624 {
1625 // A negative margin just produces a smaller rect.
1626 VECTOR2I effectiveSize = r->GetSize() + effectiveMargin;
1627
1628 if( effectiveSize.x > 0 && effectiveSize.y > 0 )
1629 m_gal->DrawRectangle( pos - effectiveMargin, pos + effectiveSize );
1630 }
1631 else if( effectiveMargin.x > 0 )
1632 {
1633 // A positive margin produces a larger rect, but with rounded corners
1634 m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
1635
1636 // Use segments to produce the margin with rounded corners
1637 m_gal->DrawSegment( pos,
1638 pos + VECTOR2I( r->GetWidth(), 0 ),
1639 effectiveMargin.x * 2 );
1640 m_gal->DrawSegment( pos + VECTOR2I( r->GetWidth(), 0 ),
1641 pos + r->GetSize(),
1642 effectiveMargin.x * 2 );
1643 m_gal->DrawSegment( pos + r->GetSize(),
1644 pos + VECTOR2I( 0, r->GetHeight() ),
1645 effectiveMargin.x * 2 );
1646 m_gal->DrawSegment( pos + VECTOR2I( 0, r->GetHeight() ),
1647 pos,
1648 effectiveMargin.x * 2 );
1649 }
1650 else
1651 {
1652 m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
1653 }
1654
1655 break;
1656 }
1657
1658 case SH_SIMPLE:
1659 {
1660 const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
1661
1662 if( poly->PointCount() < 2 ) // Careful of empty pads
1663 break;
1664
1665 if( margin.x < 0 ) // The poly shape must be deflated
1666 {
1667 SHAPE_POLY_SET outline;
1668 outline.NewOutline();
1669
1670 for( int ii = 0; ii < poly->PointCount(); ++ii )
1671 outline.Append( poly->CPoint( ii ) );
1672
1673 outline.Deflate( -margin.x, CORNER_STRATEGY::CHAMFER_ALL_CORNERS,
1674 m_maxError );
1675
1676 m_gal->DrawPolygon( outline );
1677 }
1678 else
1679 {
1680 m_gal->DrawPolygon( poly->Vertices() );
1681 }
1682
1683 // Now add on a rounded margin (using segments) if the margin > 0
1684 if( margin.x > 0 )
1685 {
1686 for( size_t ii = 0; ii < poly->GetSegmentCount(); ++ii )
1687 {
1688 SEG seg = poly->GetSegment( ii );
1689 m_gal->DrawSegment( seg.A, seg.B, margin.x * 2 );
1690 }
1691 }
1692
1693 break;
1694 }
1695
1696 default:
1697 // Better not get here; we already pre-flighted the shapes...
1698 break;
1699 }
1700 }
1701 }
1702 else
1703 {
1704 // This is expensive. Avoid if possible.
1705 SHAPE_POLY_SET polySet;
1706 aPad->TransformShapeToPolygon( polySet, ToLAYER_ID( aLayer ), margin.x, m_maxError,
1707 ERROR_INSIDE );
1708 m_gal->DrawPolygon( polySet );
1709 }
1710 }
1711
1712 if( ( ( pcbconfig() && pcbconfig()->m_Display.m_PadClearance ) || !pcbconfig() )
1714 {
1715 /*
1716 * Showing the clearance area is not obvious as the clearance extends from the pad on
1717 * flashed copper layers and from the hole on non-flashed copper layers. Because of this,
1718 * we choose to not display clearance lines at all on non-copper active layers as it's
1719 * not clear which we'd be displaying.
1720 */
1722
1723 if( activeLayer == aLayer && IsCopperLayer( activeLayer )
1724 && board->GetVisibleLayers().test( activeLayer ) )
1725 {
1726 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1728
1730 m_gal->SetIsStroke( true );
1731 m_gal->SetIsFill( false );
1733
1734 int clearance = aPad->GetOwnClearance( activeLayer );
1735
1736 if( aPad->FlashLayer( activeLayer ) && clearance > 0 )
1737 {
1738 auto shape = std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape( pcbLayer ) );
1739
1740 if( shape && shape->Size() == 1 && shape->Shapes()[0]->Type() == SH_SEGMENT )
1741 {
1742 const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape->Shapes()[0];
1743 m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
1744 seg->GetWidth() + 2 * clearance );
1745 }
1746 else if( shape && shape->Size() == 1 && shape->Shapes()[0]->Type() == SH_CIRCLE )
1747 {
1748 const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape->Shapes()[0];
1749 m_gal->DrawCircle( circle->GetCenter(), circle->GetRadius() + clearance );
1750 }
1751 else
1752 {
1753 SHAPE_POLY_SET polySet;
1754
1755 // Use ERROR_INSIDE because it avoids Clipper and is therefore much faster.
1756 aPad->TransformShapeToPolygon( polySet, activeLayer, clearance, m_maxError,
1757 ERROR_INSIDE );
1758
1759 if( polySet.Outline( 0 ).PointCount() > 2 ) // Careful of empty pads
1760 m_gal->DrawPolygon( polySet );
1761 }
1762 }
1763 else if( aPad->GetEffectiveHoleShape() && clearance > 0 )
1764 {
1765 std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
1766 m_gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B,
1767 slot->GetWidth() + 2 * clearance );
1768 }
1769 }
1770 }
1771}
1772
1773
1774void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
1775{
1776 COLOR4D color = m_pcbSettings.GetColor( aShape, aLayer );
1778 int thickness = getLineThickness( aShape->GetWidth() );
1779 LINE_STYLE lineStyle = aShape->GetStroke().GetLineStyle();
1780
1781 if( IsSolderMaskLayer( aLayer )
1782 && aShape->HasSolderMask()
1783 && IsExternalCopperLayer( aShape->GetLayer() ) )
1784 {
1785 thickness += aShape->GetSolderMaskExpansion() * 2;
1786 }
1787
1788 if( IsNetnameLayer( aLayer ) )
1789 {
1790 // Net names are shown only in board editor:
1791 if( m_frameType != FRAME_T::FRAME_PCB_EDITOR )
1792 return;
1793
1794 if( !pcbconfig() || pcbconfig()->m_Display.m_NetNames < 2 )
1795 return;
1796
1797 if( aShape->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
1798 return;
1799
1800 wxString netname = aShape->GetDisplayNetname();
1801
1802 if( netname.IsEmpty() )
1803 return;
1804
1805 if( aShape->GetShape() == SHAPE_T::SEGMENT )
1806 {
1807 SHAPE_SEGMENT seg( { aShape->GetStart(), aShape->GetEnd() }, aShape->GetWidth() );
1808 renderNetNameForSegment( seg, color, netname );
1809 return;
1810 }
1811
1812 // TODO: Maybe use some of the pad code?
1813
1814 return;
1815 }
1816
1817 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
1818 {
1819 color = m_pcbSettings.GetColor( aShape, aLayer );
1820 thickness = thickness + m_lockedShadowMargin;
1821 }
1822
1823 if( outline_mode )
1824 {
1825 m_gal->SetIsFill( false );
1826 m_gal->SetIsStroke( true );
1828 }
1829
1832
1833 // Note: on LAYER_LOCKED_ITEM_SHADOW always draw shadow shapes as continuous lines
1834 // otherwise the look is very strange and ugly
1835 if( lineStyle <= LINE_STYLE::FIRST_TYPE || aLayer == LAYER_LOCKED_ITEM_SHADOW )
1836 {
1837 switch( aShape->GetShape() )
1838 {
1839 case SHAPE_T::SEGMENT:
1840 if( aShape->IsProxyItem() )
1841 {
1842 std::vector<VECTOR2I> pts;
1843 VECTOR2I offset = ( aShape->GetEnd() - aShape->GetStart() ).Perpendicular();
1844 offset = offset.Resize( thickness / 2 );
1845
1846 pts.push_back( aShape->GetStart() + offset );
1847 pts.push_back( aShape->GetStart() - offset );
1848 pts.push_back( aShape->GetEnd() - offset );
1849 pts.push_back( aShape->GetEnd() + offset );
1850
1852 m_gal->DrawLine( pts[0], pts[1] );
1853 m_gal->DrawLine( pts[1], pts[2] );
1854 m_gal->DrawLine( pts[2], pts[3] );
1855 m_gal->DrawLine( pts[3], pts[0] );
1856 m_gal->DrawLine( ( pts[0] + pts[1] ) / 2, ( pts[1] + pts[2] ) / 2 );
1857 m_gal->DrawLine( ( pts[1] + pts[2] ) / 2, ( pts[2] + pts[3] ) / 2 );
1858 m_gal->DrawLine( ( pts[2] + pts[3] ) / 2, ( pts[3] + pts[0] ) / 2 );
1859 m_gal->DrawLine( ( pts[3] + pts[0] ) / 2, ( pts[0] + pts[1] ) / 2 );
1860 }
1861 else if( outline_mode )
1862 {
1863 m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
1864 }
1865 else
1866 {
1867 m_gal->SetIsFill( true );
1868 m_gal->SetIsStroke( false );
1869
1870 m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
1871 }
1872
1873 break;
1874
1875 case SHAPE_T::RECTANGLE:
1876 {
1877 std::vector<VECTOR2I> pts = aShape->GetRectCorners();
1878
1879 if( aShape->IsProxyItem() )
1880 {
1882 m_gal->DrawLine( pts[0], pts[1] );
1883 m_gal->DrawLine( pts[1], pts[2] );
1884 m_gal->DrawLine( pts[2], pts[3] );
1885 m_gal->DrawLine( pts[3], pts[0] );
1886 m_gal->DrawLine( pts[0], pts[2] );
1887 m_gal->DrawLine( pts[1], pts[3] );
1888 }
1889 else if( outline_mode )
1890 {
1891 m_gal->DrawSegment( pts[0], pts[1], thickness );
1892 m_gal->DrawSegment( pts[1], pts[2], thickness );
1893 m_gal->DrawSegment( pts[2], pts[3], thickness );
1894 m_gal->DrawSegment( pts[3], pts[0], thickness );
1895 }
1896 else
1897 {
1898 m_gal->SetIsFill( true );
1899 m_gal->SetIsStroke( false );
1900
1901 if( thickness > 0 )
1902 {
1903 m_gal->DrawSegment( pts[0], pts[1], thickness );
1904 m_gal->DrawSegment( pts[1], pts[2], thickness );
1905 m_gal->DrawSegment( pts[2], pts[3], thickness );
1906 m_gal->DrawSegment( pts[3], pts[0], thickness );
1907 }
1908
1909 if( aShape->IsFilled() )
1910 {
1911 SHAPE_POLY_SET poly;
1912 poly.NewOutline();
1913
1914 for( const VECTOR2I& pt : pts )
1915 poly.Append( pt );
1916
1917 if( thickness < 0 )
1918 {
1919 poly.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
1920 m_maxError );
1921 }
1922
1923 m_gal->DrawPolygon( poly );
1924 }
1925 }
1926
1927 break;
1928 }
1929
1930 case SHAPE_T::ARC:
1931 {
1932 EDA_ANGLE startAngle;
1933 EDA_ANGLE endAngle;
1934 aShape->CalcArcAngles( startAngle, endAngle );
1935
1936 if( outline_mode )
1937 {
1938 m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(), startAngle,
1939 endAngle - startAngle, thickness, m_maxError );
1940 }
1941 else
1942 {
1943 m_gal->SetIsFill( true );
1944 m_gal->SetIsStroke( false );
1945
1946 m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(), startAngle,
1947 endAngle - startAngle, thickness, m_maxError );
1948 }
1949 break;
1950 }
1951
1952 case SHAPE_T::CIRCLE:
1953 if( outline_mode )
1954 {
1955 m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() - thickness / 2 );
1956 m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() + thickness / 2 );
1957 }
1958 else
1959 {
1960 m_gal->SetIsFill( aShape->IsFilled() );
1961 m_gal->SetIsStroke( thickness > 0 );
1962 m_gal->SetLineWidth( thickness );
1963
1964 int radius = aShape->GetRadius();
1965
1966 if( thickness < 0 )
1967 {
1968 radius += thickness / 2;
1969 radius = std::max( radius, 0 );
1970 }
1971
1972 m_gal->DrawCircle( aShape->GetStart(), radius );
1973 }
1974 break;
1975
1976 case SHAPE_T::POLY:
1977 {
1978 SHAPE_POLY_SET& shape = const_cast<PCB_SHAPE*>( aShape )->GetPolyShape();
1979
1980 if( shape.OutlineCount() == 0 )
1981 break;
1982
1983 if( outline_mode )
1984 {
1985 for( int ii = 0; ii < shape.OutlineCount(); ++ii )
1986 m_gal->DrawSegmentChain( shape.Outline( ii ), thickness );
1987 }
1988 else
1989 {
1990 m_gal->SetIsFill( true );
1991 m_gal->SetIsStroke( false );
1992
1993 if( thickness > 0 )
1994 {
1995 for( int ii = 0; ii < shape.OutlineCount(); ++ii )
1996 m_gal->DrawSegmentChain( shape.Outline( ii ), thickness );
1997 }
1998
1999 if( aShape->IsFilled() )
2000 {
2001 // On Opengl, a not convex filled polygon is usually drawn by using triangles
2002 // as primitives. CacheTriangulation() can create basic triangle primitives to
2003 // draw the polygon solid shape on Opengl. GLU tessellation is much slower,
2004 // so currently we are using our tessellation.
2005 if( m_gal->IsOpenGlEngine() && !shape.IsTriangulationUpToDate() )
2006 shape.CacheTriangulation( true, true );
2007
2008
2009 if( thickness >= 0 )
2010 {
2011 m_gal->DrawPolygon( shape );
2012 }
2013 else
2014 {
2015 SHAPE_POLY_SET deflated_shape = shape;
2016 deflated_shape.Inflate( thickness / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS,
2017 m_maxError );
2018 m_gal->DrawPolygon( deflated_shape );
2019 }
2020 }
2021 }
2022
2023 break;
2024 }
2025
2026 case SHAPE_T::BEZIER:
2027 if( outline_mode )
2028 {
2029 std::vector<VECTOR2D> output;
2030 std::vector<VECTOR2D> pointCtrl;
2031
2032 pointCtrl.push_back( aShape->GetStart() );
2033 pointCtrl.push_back( aShape->GetBezierC1() );
2034 pointCtrl.push_back( aShape->GetBezierC2() );
2035 pointCtrl.push_back( aShape->GetEnd() );
2036
2037 BEZIER_POLY converter( pointCtrl );
2038 converter.GetPoly( output, m_maxError );
2039
2040 m_gal->DrawSegmentChain( aShape->GetBezierPoints(), thickness );
2041 }
2042 else
2043 {
2044 m_gal->SetIsFill( aShape->IsFilled() );
2045 m_gal->SetIsStroke( thickness > 0 );
2046 m_gal->SetLineWidth( thickness );
2047
2048 if( aShape->GetBezierPoints().size() > 2 )
2049 {
2050 m_gal->DrawPolygon( aShape->GetBezierPoints() );
2051 }
2052 else
2053 {
2054 m_gal->DrawCurve( VECTOR2D( aShape->GetStart() ),
2055 VECTOR2D( aShape->GetBezierC1() ),
2056 VECTOR2D( aShape->GetBezierC2() ),
2057 VECTOR2D( aShape->GetEnd() ), m_maxError );
2058 }
2059 }
2060
2061 break;
2062
2063 case SHAPE_T::UNDEFINED:
2064 break;
2065 }
2066 }
2067 else
2068 {
2069 if( !outline_mode )
2070 {
2071 m_gal->SetIsFill( true );
2072 m_gal->SetIsStroke( false );
2073 }
2074
2075 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
2076
2077 for( SHAPE* shape : shapes )
2078 {
2079 STROKE_PARAMS::Stroke( shape, lineStyle, getLineThickness( aShape->GetWidth() ),
2081 [&]( const VECTOR2I& a, const VECTOR2I& b )
2082 {
2083 m_gal->DrawSegment( a, b, thickness );
2084 } );
2085 }
2086
2087 for( SHAPE* shape : shapes )
2088 delete shape;
2089 }
2090}
2091
2092
2093void PCB_PAINTER::strokeText( const wxString& aText, const VECTOR2I& aPosition,
2094 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
2095{
2096 KIFONT::FONT* font = aAttrs.m_Font;
2097
2098 if( !font )
2099 font = KIFONT::FONT::GetFont( wxEmptyString, aAttrs.m_Bold, aAttrs.m_Italic );
2100
2101 m_gal->SetIsFill( font->IsOutline() );
2102 m_gal->SetIsStroke( font->IsStroke() );
2103
2104 VECTOR2I pos( aPosition );
2105 VECTOR2I fudge( KiROUND( 0.16 * aAttrs.m_StrokeWidth ), 0 );
2106
2107 RotatePoint( fudge, aAttrs.m_Angle );
2108
2109 if( ( aAttrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && !aAttrs.m_Mirrored )
2110 || ( aAttrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && aAttrs.m_Mirrored ) )
2111 {
2112 pos -= fudge;
2113 }
2114 else if( ( aAttrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && !aAttrs.m_Mirrored )
2115 || ( aAttrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && aAttrs.m_Mirrored ) )
2116 {
2117 pos += fudge;
2118 }
2119
2120 font->Draw( m_gal, aText, pos, aAttrs, aFontMetrics );
2121}
2122
2123
2124void PCB_PAINTER::draw( const PCB_REFERENCE_IMAGE* aBitmap, int aLayer )
2125{
2126 m_gal->Save();
2127
2128 const REFERENCE_IMAGE& refImg = aBitmap->GetReferenceImage();
2129 m_gal->Translate( refImg.GetPosition() );
2130
2131 // When the image scale factor is not 1.0, we need to modify the actual as the image scale
2132 // factor is similar to a local zoom
2133 const double img_scale = refImg.GetImageScale();
2134
2135 if( img_scale != 1.0 )
2136 m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
2137
2138 if( aBitmap->IsSelected() || aBitmap->IsBrightened() )
2139 {
2141 m_gal->SetIsStroke( true );
2144 m_gal->SetIsFill( false );
2145
2146 // Draws a bounding box.
2147 VECTOR2D bm_size( refImg.GetSize() );
2148 // bm_size is the actual image size in UI.
2149 // but m_gal scale was previously set to img_scale
2150 // so recalculate size relative to this image size.
2151 bm_size.x /= img_scale;
2152 bm_size.y /= img_scale;
2153 VECTOR2D origin( -bm_size.x / 2.0, -bm_size.y / 2.0 );
2154 VECTOR2D end = origin + bm_size;
2155
2156 m_gal->DrawRectangle( origin, end );
2157
2158 // Hard code reference images as opaque when selected. Otherwise cached layers will
2159 // not be rendered under the selected image because cached layers are rendered after
2160 // non-cached layers (e.g. bitmaps), which will have a closer Z order.
2161 m_gal->DrawBitmap( refImg.GetImage(), 1.0 );
2162 }
2163 else
2164 m_gal->DrawBitmap( refImg.GetImage(),
2165 m_pcbSettings.GetColor( aBitmap, aBitmap->GetLayer() ).a );
2166
2167 m_gal->Restore();
2168}
2169
2170
2171void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
2172{
2173 wxString resolvedText( aText->GetShownText( true ) );
2174
2175 if( resolvedText.Length() == 0 || !aText->GetAttributes().m_Visible )
2176 return;
2177
2178 if( aLayer == LAYER_LOCKED_ITEM_SHADOW ) // happens only if locked
2179 {
2180 const COLOR4D color = m_pcbSettings.GetColor( aText, aLayer );
2181
2182 m_gal->SetIsFill( true );
2183 m_gal->SetIsStroke( true );
2187
2188 SHAPE_POLY_SET poly;
2189 aText->TransformShapeToPolygon( poly, aText->GetLayer(), 0, m_maxError, ERROR_OUTSIDE );
2190 m_gal->DrawPolygon( poly );
2191
2192 return;
2193 }
2194
2195 const KIFONT::METRICS& metrics = aText->GetFontMetrics();
2196 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
2197 const COLOR4D& color = m_pcbSettings.GetColor( aText, aLayer );
2198 bool outline_mode = !viewer_settings()->m_ViewersDisplay.m_DisplayTextFill;
2199
2200 KIFONT::FONT* font = aText->GetFont();
2201
2202 if( !font )
2203 {
2205 aText->IsItalic() );
2206 }
2207
2210 attrs.m_Angle = aText->GetDrawRotation();
2211
2212 if( aText->IsKnockout() )
2213 {
2214 SHAPE_POLY_SET finalPoly;
2215 aText->TransformTextToPolySet( finalPoly, 0, m_maxError, ERROR_INSIDE );
2216 finalPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
2217
2218 m_gal->SetIsStroke( false );
2219 m_gal->SetIsFill( true );
2220 m_gal->DrawPolygon( finalPoly );
2221 }
2222 else
2223 {
2224 if( outline_mode )
2226 else
2228
2229 if( m_gal->IsFlippedX() && !aText->IsSideSpecific() )
2230 {
2231 VECTOR2I textPos = aText->GetTextPos();
2232 VECTOR2I textWidth = VECTOR2I( aText->GetTextBox().GetWidth(), 0 );
2233 RotatePoint( textWidth, VECTOR2I( 0, 0 ), aText->GetDrawRotation() );
2234
2235 if( attrs.m_Mirrored )
2236 textPos -= textWidth;
2237 else
2238 textPos += textWidth;
2239
2240 attrs.m_Mirrored = !attrs.m_Mirrored;
2241 strokeText( resolvedText, textPos, attrs, metrics );
2242 return;
2243 }
2244
2245 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2246
2247 if( font->IsOutline() )
2248 cache = aText->GetRenderCache( font, resolvedText );
2249
2250 if( cache )
2251 {
2253 m_gal->DrawGlyphs( *cache );
2254 }
2255 else
2256 {
2257 strokeText( resolvedText, aText->GetTextPos(), attrs, metrics );
2258 }
2259 }
2260
2261 // Draw the umbilical line for texts in footprints
2262 FOOTPRINT* fp_parent = aText->GetParentFootprint();
2263
2264 if( fp_parent && aText->IsSelected() )
2265 {
2268 m_gal->DrawLine( aText->GetTextPos(), fp_parent->GetPosition() );
2269 }
2270}
2271
2272
2273void PCB_PAINTER::draw( const PCB_TEXTBOX* aTextBox, int aLayer )
2274{
2275 if( aTextBox->Type() == PCB_TABLECELL_T )
2276 {
2277 const PCB_TABLECELL* cell = static_cast<const PCB_TABLECELL*>( aTextBox );
2278
2279 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
2280 return;
2281 }
2282
2283 COLOR4D color = m_pcbSettings.GetColor( aTextBox, aLayer );
2284 int thickness = getLineThickness( aTextBox->GetWidth() );
2285 LINE_STYLE lineStyle = aTextBox->GetStroke().GetLineStyle();
2286 wxString resolvedText( aTextBox->GetShownText( true ) );
2287
2288 KIFONT::FONT* font = aTextBox->GetFont();
2289
2290 if( !font )
2291 {
2293 aTextBox->IsItalic() );
2294 }
2295
2296 if( aLayer == LAYER_LOCKED_ITEM_SHADOW ) // happens only if locked
2297 {
2298 const COLOR4D sh_color = m_pcbSettings.GetColor( aTextBox, aLayer );
2299
2300 m_gal->SetIsFill( true );
2301 m_gal->SetIsStroke( false );
2302 m_gal->SetFillColor( sh_color );
2303 m_gal->SetStrokeColor( sh_color );
2304
2305 // Draw the box with a larger thickness than box thickness to show
2306 // the shadow mask
2307 std::vector<VECTOR2I> pts = aTextBox->GetCorners();
2308 int line_thickness = std::max( thickness*3, pcbIUScale.mmToIU( 0.2 ) );
2309
2310 std::deque<VECTOR2D> dpts;
2311
2312 for( const VECTOR2I& pt : pts )
2313 dpts.push_back( VECTOR2D( pt ) );
2314
2315 dpts.push_back( VECTOR2D( pts[0] ) );
2316
2317 m_gal->SetIsStroke( true );
2318 m_gal->SetLineWidth( line_thickness );
2319 m_gal->DrawPolygon( dpts );
2320 }
2321
2322 if( aTextBox->Type() == PCB_TABLECELL_T )
2323 {
2324 // Selection for tables is done with a background wash, so pass in nullptr to GetColor()
2325 // so we just get the "normal" (un-selected/un-brightened) color for the borders.
2326 color = m_pcbSettings.GetColor( nullptr, aLayer );
2327 }
2328
2331 m_gal->SetIsFill( true );
2332 m_gal->SetIsStroke( false );
2333
2334 if( aTextBox->Type() != PCB_TABLECELL_T && aTextBox->IsBorderEnabled() )
2335 {
2336 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2337 {
2338 if( thickness > 0 )
2339 {
2340 std::vector<VECTOR2I> pts = aTextBox->GetCorners();
2341
2342 for( size_t ii = 0; ii < pts.size(); ++ii )
2343 m_gal->DrawSegment( pts[ii], pts[( ii + 1 ) % pts.size()], thickness );
2344 }
2345 }
2346 else
2347 {
2348 std::vector<SHAPE*> shapes = aTextBox->MakeEffectiveShapes( true );
2349
2350 for( SHAPE* shape : shapes )
2351 {
2352 STROKE_PARAMS::Stroke( shape, lineStyle, thickness, &m_pcbSettings,
2353 [&]( const VECTOR2I& a, const VECTOR2I& b )
2354 {
2355 m_gal->DrawSegment( a, b, thickness );
2356 } );
2357 }
2358
2359 for( SHAPE* shape : shapes )
2360 delete shape;
2361 }
2362 }
2363
2364 if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
2365 {
2366 // For now, the textbox is a filled shape.
2367 // so the text drawn on LAYER_LOCKED_ITEM_SHADOW with a thick width is disabled
2368 // If enabled, the thick text position must be offsetted to be exactly on the
2369 // initial text, which is not easy, depending on its rotation and justification.
2370#if 0
2371 const COLOR4D sh_color = m_pcbSettings.GetColor( aTextBox, aLayer );
2372 m_gal->SetFillColor( sh_color );
2373 m_gal->SetStrokeColor( sh_color );
2374 attrs.m_StrokeWidth += m_lockedShadowMargin;
2375#else
2376 return;
2377#endif
2378 }
2379
2380 if( resolvedText.Length() == 0 )
2381 return;
2382
2383 const KIFONT::METRICS& metrics = aTextBox->GetFontMetrics();
2384 TEXT_ATTRIBUTES attrs = aTextBox->GetAttributes();
2386
2387 if( m_gal->IsFlippedX() && !aTextBox->IsSideSpecific() )
2388 {
2389 attrs.m_Mirrored = !attrs.m_Mirrored;
2390 strokeText( resolvedText, aTextBox->GetDrawPos( true ), attrs, metrics );
2391 return;
2392 }
2393
2394 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2395
2396 if( font->IsOutline() )
2397 cache = aTextBox->GetRenderCache( font, resolvedText );
2398
2399 if( cache )
2400 {
2402 m_gal->DrawGlyphs( *cache );
2403 }
2404 else
2405 {
2406 strokeText( resolvedText, aTextBox->GetDrawPos(), attrs, metrics );
2407 }
2408}
2409
2410
2411void PCB_PAINTER::draw( const PCB_TABLE* aTable, int aLayer )
2412{
2413 for( PCB_TABLECELL* cell : aTable->GetCells() )
2414 draw( static_cast<PCB_TEXTBOX*>( cell ), aLayer );
2415
2416 VECTOR2I pos = aTable->GetPosition();
2417 VECTOR2I end = aTable->GetEnd();
2418 EDA_ANGLE drawOrientation = aTable->GetOrientation();
2419
2420 // Selection for tables is done with a background wash, so pass in nullptr to GetColor()
2421 // so we just get the "normal" (un-selected/un-brightened) color for the borders.
2422 COLOR4D color = m_pcbSettings.GetColor( nullptr, aLayer );
2423 int lineWidth;
2424 LINE_STYLE lineStyle;
2425
2426 auto setupStroke =
2427 [&]( const STROKE_PARAMS& stroke )
2428 {
2429 lineWidth = getLineThickness( stroke.GetWidth() );
2430 lineStyle = stroke.GetLineStyle();
2431
2432 m_gal->SetIsFill( false );
2433 m_gal->SetIsStroke( true );
2435 m_gal->SetLineWidth( lineWidth );
2436 };
2437
2438 auto strokeShape =
2439 [&]( const SHAPE& shape )
2440 {
2441 STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, &m_pcbSettings,
2442 [&]( VECTOR2I a, VECTOR2I b )
2443 {
2444 RotatePoint( a, pos, drawOrientation );
2445 RotatePoint( b, pos, drawOrientation );
2446
2447 // DrawLine has problem with 0 length lines so enforce minimum
2448 if( a == b )
2449 m_gal->DrawLine( a+1, b );
2450 else
2451 m_gal->DrawLine( a, b );
2452 } );
2453 };
2454
2455 auto strokeLine =
2456 [&]( VECTOR2I ptA, VECTOR2I ptB )
2457 {
2458 RotatePoint( ptA, pos, drawOrientation );
2459 RotatePoint( ptB, pos, drawOrientation );
2460
2461 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2462 {
2463 m_gal->DrawLine( ptA, ptB );
2464 }
2465 else
2466 {
2467 SHAPE_SEGMENT seg( ptA, ptB );
2468 strokeShape( seg );
2469 }
2470 };
2471
2472 auto strokeRect =
2473 [&]( VECTOR2I ptA, VECTOR2I ptB )
2474 {
2475 RotatePoint( ptA, pos, drawOrientation );
2476 RotatePoint( ptB, pos, drawOrientation );
2477
2478 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2479 {
2480 m_gal->DrawRectangle( ptA, ptB );
2481 }
2482 else
2483 {
2484 SHAPE_RECT rect( BOX2I( ptA, ptB - ptA ) );
2485 strokeShape( rect );
2486 }
2487 };
2488
2489 if( aTable->GetSeparatorsStroke().GetWidth() >= 0 )
2490 {
2491 setupStroke( aTable->GetSeparatorsStroke() );
2492
2493 if( aTable->StrokeColumns() )
2494 {
2495 int x = pos.x;
2496
2497 for( int col = 0; col < aTable->GetColCount() - 1; ++col )
2498 {
2499 int y = pos.y;
2500
2501 for( int row = 0; row < aTable->GetRowCount(); ++row )
2502 {
2503 PCB_TABLECELL* cell = aTable->GetCell( row, col );
2504 int rowHeight = aTable->GetRowHeight( row );
2505
2506 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
2507 strokeLine( VECTOR2I( x, y ), VECTOR2I( x, y + rowHeight ) );
2508
2509 y += rowHeight;
2510 }
2511
2512 x += aTable->GetColWidth( col );
2513 }
2514 }
2515
2516 if( aTable->StrokeRows() )
2517 {
2518 int y = pos.y;
2519
2520 for( int row = 0; row < aTable->GetRowCount() - 1; ++row )
2521 {
2522 int x = pos.x;
2523
2524 for( int col = 0; col < aTable->GetColCount(); ++col )
2525 {
2526 PCB_TABLECELL* cell = aTable->GetCell( row, col );
2527 int colWidth = aTable->GetColWidth( col );
2528
2529 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
2530 strokeLine( VECTOR2I( x, y ), VECTOR2I( x + colWidth, y ) );
2531
2532 x += colWidth;
2533 }
2534
2535 y += aTable->GetRowHeight( row );
2536 }
2537 }
2538 }
2539
2540 if( aTable->GetBorderStroke().GetWidth() >= 0 )
2541 {
2542 setupStroke( aTable->GetBorderStroke() );
2543
2544 if( aTable->StrokeHeader() )
2545 {
2546 int headerBottom = pos.y + aTable->GetRowHeight( 0 );
2547
2548 strokeLine( VECTOR2I( pos.x, headerBottom ), VECTOR2I( end.x, headerBottom ) );
2549 }
2550
2551 if( aTable->StrokeExternal() )
2552 strokeRect( pos, end );
2553 }
2554
2555 // Highlight selected tablecells with a background wash.
2556 for( PCB_TABLECELL* cell : aTable->GetCells() )
2557 {
2558 if( aTable->IsSelected() || cell->IsSelected() )
2559 {
2560 std::vector<VECTOR2I> corners = cell->GetCorners();
2561 std::deque<VECTOR2D> pts;
2562
2563 pts.insert( pts.end(), corners.begin(), corners.end() );
2564
2565 m_gal->SetFillColor( color.WithAlpha( 0.5 ) );
2566 m_gal->SetIsFill( true );
2567 m_gal->SetIsStroke( false );
2568 m_gal->DrawPolygon( pts );
2569 }
2570 }
2571}
2572
2573
2574void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer )
2575{
2576 if( aLayer == LAYER_ANCHOR )
2577 {
2578 const COLOR4D color = m_pcbSettings.GetColor( aFootprint, aLayer );
2579
2580 // Keep the size and width constant, not related to the scale because the anchor
2581 // is just a marker on screen
2582 double anchorSize = 5.0 / m_gal->GetWorldScale(); // 5 pixels size
2583 double anchorThickness = 1.0 / m_gal->GetWorldScale(); // 1 pixels width
2584
2585 // Draw anchor
2586 m_gal->SetIsFill( false );
2587 m_gal->SetIsStroke( true );
2589 m_gal->SetLineWidth( anchorThickness );
2590
2591 VECTOR2D center = aFootprint->GetPosition();
2592 m_gal->DrawLine( center - VECTOR2D( anchorSize, 0 ), center + VECTOR2D( anchorSize, 0 ) );
2593 m_gal->DrawLine( center - VECTOR2D( 0, anchorSize ), center + VECTOR2D( 0, anchorSize ) );
2594 }
2595
2596 if( aLayer == LAYER_LOCKED_ITEM_SHADOW && m_frameType == FRAME_PCB_EDITOR ) // happens only if locked
2597 {
2598 const COLOR4D color = m_pcbSettings.GetColor( aFootprint, aLayer );
2599
2600 m_gal->SetIsFill( true );
2601 m_gal->SetIsStroke( false );
2603
2604#if 0 // GetBoundingHull() can be very slow, especially for logos imported from graphics
2605 const SHAPE_POLY_SET& poly = aFootprint->GetBoundingHull();
2606 m_gal->DrawPolygon( poly );
2607#else
2608 BOX2I bbox = aFootprint->GetBoundingBox( false );
2609 VECTOR2I topLeft = bbox.GetPosition();
2610 VECTOR2I botRight = bbox.GetPosition() + bbox.GetSize();
2611
2612 m_gal->DrawRectangle( topLeft, botRight );
2613
2614 // Use segments to produce a margin with rounded corners
2615 m_gal->DrawSegment( topLeft, VECTOR2I( botRight.x, topLeft.y ), m_lockedShadowMargin );
2616 m_gal->DrawSegment( VECTOR2I( botRight.x, topLeft.y ), botRight, m_lockedShadowMargin );
2617 m_gal->DrawSegment( botRight, VECTOR2I( topLeft.x, botRight.y ), m_lockedShadowMargin );
2618 m_gal->DrawSegment( VECTOR2I( topLeft.x, botRight.y ), topLeft, m_lockedShadowMargin );
2619#endif
2620 }
2621
2622 if( aLayer == LAYER_CONFLICTS_SHADOW )
2623 {
2624 const SHAPE_POLY_SET& frontpoly = aFootprint->GetCourtyard( F_CrtYd );
2625 const SHAPE_POLY_SET& backpoly = aFootprint->GetCourtyard( B_CrtYd );
2626
2627 const COLOR4D color = m_pcbSettings.GetColor( aFootprint, aLayer );
2628
2629 m_gal->SetIsFill( true );
2630 m_gal->SetIsStroke( false );
2632
2633 if( frontpoly.OutlineCount() > 0 )
2634 m_gal->DrawPolygon( frontpoly );
2635
2636 if( backpoly.OutlineCount() > 0 )
2637 m_gal->DrawPolygon( backpoly );
2638 }
2639}
2640
2641
2642void PCB_PAINTER::draw( const PCB_GROUP* aGroup, int aLayer )
2643{
2644 if( aLayer == LAYER_ANCHOR )
2645 {
2646 if( aGroup->IsSelected() && !( aGroup->GetParent() && aGroup->GetParent()->IsSelected() ) )
2647 {
2648 // Selected on our own; draw enclosing box
2649 }
2650 else if( aGroup->IsEntered() )
2651 {
2652 // Entered group; draw enclosing box
2653 }
2654 else
2655 {
2656 // Neither selected nor entered; draw nothing at the group level (ie: only draw
2657 // its members)
2658 return;
2659 }
2660
2661 const COLOR4D color = m_pcbSettings.GetColor( aGroup, LAYER_ANCHOR );
2662
2665
2666 BOX2I bbox = aGroup->GetBoundingBox();
2667 VECTOR2I topLeft = bbox.GetPosition();
2668 VECTOR2I width = VECTOR2I( bbox.GetWidth(), 0 );
2669 VECTOR2I height = VECTOR2I( 0, bbox.GetHeight() );
2670
2671 m_gal->DrawLine( topLeft, topLeft + width );
2672 m_gal->DrawLine( topLeft + width, topLeft + width + height );
2673 m_gal->DrawLine( topLeft + width + height, topLeft + height );
2674 m_gal->DrawLine( topLeft + height, topLeft );
2675
2676 wxString name = aGroup->GetName();
2677
2678 if( name.IsEmpty() )
2679 return;
2680
2681 int ptSize = 12;
2682 int scaledSize = abs( KiROUND( m_gal->GetScreenWorldMatrix().GetScale().x * ptSize ) );
2683 int unscaledSize = pcbIUScale.MilsToIU( ptSize );
2684
2685 // Scale by zoom a bit, but not too much
2686 int textSize = ( scaledSize + ( unscaledSize * 2 ) ) / 3;
2687 VECTOR2I textOffset = VECTOR2I( width.x / 2, -KiROUND( textSize * 0.5 ) );
2688 VECTOR2I titleHeight = VECTOR2I( 0, KiROUND( textSize * 2.0 ) );
2689
2690 if( PrintableCharCount( name ) * textSize < bbox.GetWidth() )
2691 {
2692 m_gal->DrawLine( topLeft, topLeft - titleHeight );
2693 m_gal->DrawLine( topLeft - titleHeight, topLeft + width - titleHeight );
2694 m_gal->DrawLine( topLeft + width - titleHeight, topLeft + width );
2695
2696 TEXT_ATTRIBUTES attrs;
2697 attrs.m_Italic = true;
2700 attrs.m_Size = VECTOR2I( textSize, textSize );
2701 attrs.m_StrokeWidth = GetPenSizeForNormal( textSize );
2702
2703 KIFONT::FONT::GetFont()->Draw( m_gal, aGroup->GetName(), topLeft + textOffset, attrs,
2704 aGroup->GetFontMetrics() );
2705 }
2706 }
2707}
2708
2709
2710void PCB_PAINTER::draw( const ZONE* aZone, int aLayer )
2711{
2712 if( aLayer == LAYER_CONFLICTS_SHADOW )
2713 {
2714 COLOR4D color = m_pcbSettings.GetColor( aZone, aLayer );
2715
2716 m_gal->SetIsFill( true );
2717 m_gal->SetIsStroke( false );
2719
2720 m_gal->DrawPolygon( aZone->Outline()->Outline( 0 ) );
2721 return;
2722 }
2723
2724 /*
2725 * aLayer will be the virtual zone layer (LAYER_ZONE_START, ... in GAL_LAYER_ID)
2726 * This is used for draw ordering in the GAL.
2727 * The color for the zone comes from the associated copper layer ( aLayer - LAYER_ZONE_START )
2728 * and the visibility comes from the combination of that copper layer and LAYER_ZONES
2729 */
2730 PCB_LAYER_ID layer;
2731
2732 if( IsZoneFillLayer( aLayer ) )
2733 layer = ToLAYER_ID( aLayer - LAYER_ZONE_START );
2734 else
2735 layer = ToLAYER_ID( aLayer );
2736
2737 if( !aZone->IsOnLayer( layer ) )
2738 return;
2739
2740 COLOR4D color = m_pcbSettings.GetColor( aZone, layer );
2741 std::deque<VECTOR2D> corners;
2743
2744 // Draw the outline
2745 if( !IsZoneFillLayer( aLayer ) )
2746 {
2747 const SHAPE_POLY_SET* outline = aZone->Outline();
2748 bool allowDrawOutline = aZone->GetHatchStyle() != ZONE_BORDER_DISPLAY_STYLE::INVISIBLE_BORDER;
2749
2750 if( allowDrawOutline && !m_pcbSettings.m_isPrinting && outline && outline->OutlineCount() > 0 )
2751 {
2752 m_gal->SetStrokeColor( color.a > 0.0 ? color.WithAlpha( 1.0 ) : color );
2753 m_gal->SetIsFill( false );
2754 m_gal->SetIsStroke( true );
2756
2757 // Draw each contour (main contour and holes)
2758
2759 /*
2760 * m_gal->DrawPolygon( *outline );
2761 * should be enough, but currently does not work to draw holes contours in a complex
2762 * polygon so each contour is draw as a simple polygon
2763 */
2764
2765 // Draw the main contour(s?)
2766 for( int ii = 0; ii < outline->OutlineCount(); ++ii )
2767 {
2768 m_gal->DrawPolyline( outline->COutline( ii ) );
2769
2770 // Draw holes
2771 int holes_count = outline->HoleCount( ii );
2772
2773 for( int jj = 0; jj < holes_count; ++jj )
2774 m_gal->DrawPolyline( outline->CHole( ii, jj ) );
2775 }
2776
2777 // Draw hatch lines
2778 for( const SEG& hatchLine : aZone->GetHatchLines() )
2779 m_gal->DrawLine( hatchLine.A, hatchLine.B );
2780 }
2781 }
2782
2783 // Draw the filling
2784 if( IsZoneFillLayer( aLayer )
2785 && ( displayMode == ZONE_DISPLAY_MODE::SHOW_FILLED
2786 || displayMode == ZONE_DISPLAY_MODE::SHOW_FRACTURE_BORDERS
2787 || displayMode == ZONE_DISPLAY_MODE::SHOW_TRIANGULATION ) )
2788 {
2789 const std::shared_ptr<SHAPE_POLY_SET>& polySet = aZone->GetFilledPolysList( layer );
2790
2791 if( polySet->OutlineCount() == 0 ) // Nothing to draw
2792 return;
2793
2796 m_gal->SetLineWidth( 0 );
2797
2798 if( displayMode == ZONE_DISPLAY_MODE::SHOW_FILLED )
2799 {
2800 m_gal->SetIsFill( true );
2801 m_gal->SetIsStroke( false );
2802 }
2803 else
2804 {
2805 m_gal->SetIsFill( false );
2806 m_gal->SetIsStroke( true );
2807 }
2808
2809 // On Opengl, a not convex filled polygon is usually drawn by using triangles
2810 // as primitives. CacheTriangulation() can create basic triangle primitives to
2811 // draw the polygon solid shape on Opengl. GLU tessellation is much slower,
2812 // so currently we are using our tessellation.
2813 if( m_gal->IsOpenGlEngine() && !polySet->IsTriangulationUpToDate() )
2814 polySet->CacheTriangulation( true, true );
2815
2816 m_gal->DrawPolygon( *polySet, displayMode == ZONE_DISPLAY_MODE::SHOW_TRIANGULATION );
2817 }
2818}
2819
2820
2821void PCB_PAINTER::draw( const PCB_DIMENSION_BASE* aDimension, int aLayer )
2822{
2823 const COLOR4D& color = m_pcbSettings.GetColor( aDimension, aLayer );
2824
2827 m_gal->SetIsFill( false );
2828 m_gal->SetIsStroke( true );
2829
2831
2832 if( outline_mode )
2834 else
2836
2837 // Draw dimension shapes
2838 // TODO(JE) lift this out
2839 for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
2840 {
2841 switch( shape->Type() )
2842 {
2843 case SH_SEGMENT:
2844 {
2845 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
2846 m_gal->DrawLine( seg.A, seg.B );
2847 break;
2848 }
2849
2850 case SH_CIRCLE:
2851 {
2852 int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
2853 m_gal->DrawCircle( shape->Centre(), radius );
2854 break;
2855 }
2856
2857 default:
2858 break;
2859 }
2860 }
2861
2862 // Draw text
2863 wxString resolvedText = aDimension->GetShownText( true );
2864 TEXT_ATTRIBUTES attrs = aDimension->GetAttributes();
2865
2866 if( m_gal->IsFlippedX() && !aDimension->IsSideSpecific() )
2867 attrs.m_Mirrored = !attrs.m_Mirrored;
2868
2869 if( outline_mode )
2871 else
2873
2874 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2875
2876 if( aDimension->GetFont() && aDimension->GetFont()->IsOutline() )
2877 cache = aDimension->GetRenderCache( aDimension->GetFont(), resolvedText );
2878
2879 if( cache )
2880 {
2881 for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *cache )
2882 m_gal->DrawGlyph( *glyph.get() );
2883 }
2884 else
2885 {
2886 strokeText( resolvedText, aDimension->GetTextPos(), attrs, aDimension->GetFontMetrics() );
2887 }
2888}
2889
2890
2891void PCB_PAINTER::draw( const PCB_TARGET* aTarget )
2892{
2893 const COLOR4D& strokeColor = m_pcbSettings.GetColor( aTarget, aTarget->GetLayer() );
2894 VECTOR2D position( aTarget->GetPosition() );
2895 double size, radius;
2896
2897 m_gal->SetLineWidth( getLineThickness( aTarget->GetWidth() ) );
2898 m_gal->SetStrokeColor( strokeColor );
2899 m_gal->SetIsFill( false );
2900 m_gal->SetIsStroke( true );
2901
2902 m_gal->Save();
2903 m_gal->Translate( position );
2904
2905 if( aTarget->GetShape() )
2906 {
2907 // shape x
2908 m_gal->Rotate( M_PI / 4.0 );
2909 size = 2.0 * aTarget->GetSize() / 3.0;
2910 radius = aTarget->GetSize() / 2.0;
2911 }
2912 else
2913 {
2914 // shape +
2915 size = aTarget->GetSize() / 2.0;
2916 radius = aTarget->GetSize() / 3.0;
2917 }
2918
2919 m_gal->DrawLine( VECTOR2D( -size, 0.0 ), VECTOR2D( size, 0.0 ) );
2920 m_gal->DrawLine( VECTOR2D( 0.0, -size ), VECTOR2D( 0.0, size ) );
2921 m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), radius );
2922
2923 m_gal->Restore();
2924}
2925
2926
2927void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
2928{
2929 switch( aLayer )
2930 {
2932 case LAYER_DRC_ERROR:
2933 case LAYER_DRC_WARNING:
2934 {
2935 bool isShadow = aLayer == LAYER_MARKER_SHADOWS;
2936
2937 // Don't paint invisible markers.
2938 // It would be nice to do this through layer dependencies but we can't do an "or" there today
2939 if( aMarker->GetBoard()
2940 && !aMarker->GetBoard()->IsElementVisible( aMarker->GetColorLayer() ) )
2941 return;
2942
2943 const_cast<PCB_MARKER*>( aMarker )->SetZoom( 1.0 / sqrt( m_gal->GetZoomFactor() ) );
2944
2945 SHAPE_LINE_CHAIN polygon;
2946 aMarker->ShapeToPolygon( polygon );
2947
2949 : aMarker->GetColorLayer() );
2950
2951 m_gal->Save();
2952 m_gal->Translate( aMarker->GetPosition() );
2953
2954 if( isShadow )
2955 {
2957 m_gal->SetIsStroke( true );
2958 m_gal->SetLineWidth( aMarker->MarkerScale() );
2959 }
2960 else
2961 {
2963 m_gal->SetIsFill( true );
2964 }
2965
2966 m_gal->DrawPolygon( polygon );
2967 m_gal->Restore();
2968 return;
2969 }
2970 case LAYER_DRC_SHAPE1:
2971 case LAYER_DRC_SHAPE2:
2972 {
2973 if( !aMarker->IsBrightened() )
2974 return;
2975
2976 int arc_to_seg_error = gerbIUScale.mmToIU( 0.005 ); // Allow 5 microns
2977 m_gal->SetLineWidth( aMarker->MarkerScale() );
2978
2979 for( auto& shape :
2980 aLayer == LAYER_DRC_SHAPE1 ? aMarker->GetShapes1() : aMarker->GetShapes2() )
2981 {
2982 m_gal->SetIsFill( shape.IsFilled() );
2983 m_gal->SetIsStroke( aLayer == LAYER_DRC_SHAPE1 ? true : false );
2984 m_gal->SetStrokeColor( shape.GetLineColor() );
2985 m_gal->SetFillColor( shape.GetFillColor() );
2986
2987 switch( shape.GetShape() )
2988 {
2989 case SHAPE_T::SEGMENT:
2990 m_gal->DrawSegment( shape.GetStart(), shape.GetEnd(), shape.GetWidth() );
2991 break;
2992 case SHAPE_T::ARC:
2993 {
2994 EDA_ANGLE startAngle, endAngle;
2995 shape.CalcArcAngles( startAngle, endAngle );
2996 m_gal->DrawArcSegment( shape.GetCenter(), shape.GetRadius(), startAngle,
2997 shape.GetArcAngle(), shape.GetWidth(), arc_to_seg_error );
2998 break;
2999 }
3000 default: break;
3001 }
3002 }
3003 }
3004 }
3005}
3006
3007
int color
Definition: DXF_plotter.cpp:58
const char * name
Definition: DXF_plotter.cpp:57
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_OUTSIDE
Definition: approximation.h:33
@ ERROR_INSIDE
Definition: approximation.h:34
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr EDA_IU_SCALE gerbIUScale
Definition: base_units.h:107
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
BOX2< VECTOR2I > BOX2I
Definition: box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
const wxString & GetDisplayNetname() const
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
Container for design settings for a BOARD object.
int GetHolePlatingThickness() const
Pad & via drills are finish size.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:237
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:133
virtual bool IsKnockout() const
Definition: board_item.h:324
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:244
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:299
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
const KIFONT::METRICS & GetFontMetrics() const
Definition: board_item.cpp:100
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:215
bool IsSideSpecific() const
Definition: board_item.cpp:149
virtual bool IsOnCopperLayer() const
Definition: board_item.h:150
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:775
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
Definition: board.cpp:789
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:841
int GetCopperLayerCount() const
Definition: board.cpp:738
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:892
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr void SetOrigin(const Vec &pos)
Definition: box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr void SetEnd(coord_type x, coord_type y)
Definition: box2.h:297
Color settings are a bit different than most of the settings objects in that there can be more than o...
COLOR4D GetColor(int aLayer) const
APPEARANCE m_Appearance
EDA_ANGLE Normalize90()
Definition: eda_angle.h:249
double AsRadians() const
Definition: eda_angle.h:117
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:77
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
bool IsEntered() const
Definition: eda_item.h:111
bool IsSelected() const
Definition: eda_item.h:110
bool IsBrightened() const
Definition: eda_item.h:112
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:206
virtual VECTOR2I GetTopLeft() const
Definition: eda_shape.h:194
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition: eda_shape.h:319
bool IsFilled() const
Definition: eda_shape.h:91
void CalcArcAngles(EDA_ANGLE &aStartAngle, EDA_ANGLE &aEndAngle) const
Calc arc start and end angles such that aStartAngle < aEndAngle.
Definition: eda_shape.cpp:559
int GetRadius() const
Definition: eda_shape.cpp:575
SHAPE_T GetShape() const
Definition: eda_shape.h:125
virtual VECTOR2I GetBotRight() const
Definition: eda_shape.h:195
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:130
std::vector< VECTOR2I > GetRectCorners() const
Definition: eda_shape.cpp:1134
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition: eda_shape.h:262
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:203
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:253
bool IsItalic() const
Definition: eda_text.h:152
KIFONT::FONT * GetFont() const
Definition: eda_text.h:230
BOX2I GetTextBox(int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition: eda_text.cpp:616
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const KIFONT::FONT *aFont, const wxString &forResolvedText, const VECTOR2I &aOffset={ 0, 0 }) const
Definition: eda_text.cpp:557
const TEXT_ATTRIBUTES & GetAttributes() const
Definition: eda_text.h:214
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition: eda_text.cpp:369
bool IsBold() const
Definition: eda_text.h:167
LSET GetPrivateLayers() const
Definition: footprint.h:141
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:1443
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2847
VECTOR2I GetPosition() const override
Definition: footprint.h:224
DRAWINGS & GraphicalItems()
Definition: footprint.h:209
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1252
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition: font.cpp:146
virtual bool IsStroke() const
Definition: font.h:138
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Draw a string.
Definition: font.cpp:258
virtual bool IsOutline() const
Definition: font.h:139
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
static const COLOR4D CLEAR
Definition: color4d.h:403
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
Definition: color4d.h:226
COLOR4D Inverted() const
Returns an inverted color, alpha remains the same.
Definition: color4d.h:323
COLOR4D & Brighten(double aFactor)
Makes the color brighter by a given factor.
Definition: color4d.h:209
double a
Alpha component.
Definition: color4d.h:395
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:398
Abstract interface for drawing on a 2D-surface.
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList)
Draw a polygon.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void DrawGlyph(const KIFONT::GLYPH &aGlyph, int aNth=0, int aTotal=1)
Draw a polygon representing a font glyph.
virtual void Rotate(double aAngle)
Rotate the context.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
void SetVerticalJustify(const GR_TEXT_V_ALIGN_T aVerticalJustify)
void SetFontBold(const bool aBold)
void SetFontUnderlined(bool aUnderlined)
void SetHorizontalJustify(const GR_TEXT_H_ALIGN_T aHorizontalJustify)
double GetZoomFactor() const
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual void Translate(const VECTOR2D &aTranslation)
Translate the context.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius)
Draw a circle using world coordinates.
virtual void Restore()
Restore the context.
virtual bool IsOpenGlEngine()
Return true if the GAL engine is a OpenGL based type.
void ResetTextAttributes()
Reset text attributes to default styling.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
void SetTextMirrored(const bool aMirrored)
virtual void DrawPolyline(const std::deque< VECTOR2D > &aPointList)
Draw a polyline.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aWidth, double aMaxError)
Draw an arc segment.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
void SetGlyphSize(const VECTOR2I aSize)
virtual void DrawGlyphs(const std::vector< std::unique_ptr< KIFONT::GLYPH > > &aGlyphs)
Draw polygons representing font glyphs.
virtual void Scale(const VECTOR2D &aScale)
Scale the context.
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0)
Draw a cubic bezier spline.
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle)
Draw an arc.
void SetFontItalic(bool aItalic)
virtual void DrawBitmap(const BITMAP_BASE &aBitmap, double alphaBlend=1.0)
Draw a bitmap image.
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth)
Draw a rounded segment.
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
const VECTOR2I & GetScreenPixelSize() const
Return GAL canvas size in pixels.
virtual void Save()
Save the context.
virtual void DrawSegmentChain(const std::vector< VECTOR2D > &aPointList, double aWidth)
Draw a chain of rounded segments.
double GetWorldScale() const
Get the world scale.
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition: painter.h:59
GAL * m_gal
Instance of graphic abstraction layer that gives an interface to call commands used to draw (eg.
Definition: painter.h:102
virtual SHAPE_SEGMENT getPadHoleShape(const PAD *aPad) const
Return hole shape for a pad (internal units).
PCB_PAINTER(GAL *aGal, FRAME_T aFrameType)
int getLineThickness(int aActualThickness) const
Get the thickness to draw for a line (e.g.
void renderNetNameForSegment(const SHAPE_SEGMENT &aSeg, const COLOR4D &aColor, const wxString &aNetName) const
PCB_VIEWERS_SETTINGS_BASE * viewer_settings()
Definition: pcb_painter.cpp:83
void draw(const PCB_TRACK *aTrack, int aLayer)
virtual PAD_DRILL_SHAPE getDrillShape(const PAD *aPad) const
Return drill shape of a pad.
PCB_RENDER_SETTINGS m_pcbSettings
Definition: pcb_painter.h:235
virtual int getViaDrillSize(const PCB_VIA *aVia) const
Return drill diameter for a via (internal units).
void strokeText(const wxString &aText, const VECTOR2I &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
virtual bool Draw(const VIEW_ITEM *aItem, int aLayer) override
Takes an instance of VIEW_ITEM and passes it to a function that knows how to draw the item.
double m_zoneOpacity
Opacity override for filled zones.
Definition: pcb_painter.h:163
double m_trackOpacity
Opacity override for all tracks.
Definition: pcb_painter.h:160
double m_imageOpacity
Opacity override for user images.
Definition: pcb_painter.h:164
double m_viaOpacity
Opacity override for all types of via.
Definition: pcb_painter.h:161
ZONE_DISPLAY_MODE m_ZoneDisplayMode
Definition: pcb_painter.h:138
void LoadColors(const COLOR_SETTINGS *aSettings) override
double m_padOpacity
Opacity override for SMD pads and PTHs.
Definition: pcb_painter.h:162
void SetBackgroundColor(const COLOR4D &aColor) override
Set the background color.
Definition: pcb_painter.h:117
COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const override
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
HIGH_CONTRAST_MODE m_ContrastModeDisplay
Definition: pcb_painter.h:139
std::map< int, KIGFX::COLOR4D > m_netColors
Set of net codes that should not have their ratsnest displayed.
Definition: pcb_painter.h:154
NET_COLOR_MODE m_netColorMode
Overrides for specific netclass colors.
Definition: pcb_painter.h:148
static const double MAX_FONT_SIZE
< Maximum font size for netnames (and other dynamically shown strings)
Definition: pcb_painter.h:145
double m_filledShapeOpacity
Opacity override for graphic shapes.
Definition: pcb_painter.h:165
bool GetShowPageLimits() const override
void LoadDisplayOptions(const PCB_DISPLAY_OPTIONS &aOptions)
Load settings related to display options (high-contrast mode, full or outline modes for vias/pads/tra...
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
void SetGapLengthRatio(double aRatio)
const wxString & GetDefaultFont() const
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
PCB_LAYER_ID GetActiveLayer() const
COLOR4D m_layerColorsDark[LAYER_ID_COUNT]
COLOR4D m_layerColorsSel[LAYER_ID_COUNT]
COLOR4D m_layerColorsHi[LAYER_ID_COUNT]
virtual void update()
Precalculates extra colors for layers (e.g.
void SetDashLengthRatio(double aRatio)
COLOR4D m_layerColors[LAYER_ID_COUNT]
std::set< int > m_highlightNetcodes
std::set< int > m_highContrastLayers
bool m_hiContrastEnabled
Parameters for display modes.
bool GetDrawBoundingBoxes() const
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:84
bool IsBOARD_ITEM() const
Definition: view_item.h:100
double GetForcedTransparency() const
Definition: view_item.h:161
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
PCB_LAYER_ID ExtractLayer() const
Find the first set PCB_LAYER_ID.
Definition: lset.cpp:630
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:756
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
int MarkerScale() const
The scaling factor to convert polygonal shape coordinates to internal units.
Definition: marker_base.h:69
void ShapeToPolygon(SHAPE_LINE_CHAIN &aPolygon, int aScale=-1) const
Return the shape polygon in internal units in a SHAPE_LINE_CHAIN the coordinates are relatives to the...
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:295
A collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:44
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition: netclass.h:176
bool HasPcbColor() const
Definition: netclass.h:175
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:381
Definition: pad.h:54
int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const override
Return the pad's "own" clearance in internal units.
Definition: pad.cpp:1056
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:367
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:340
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:488
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:802
PAD_ATTRIB GetAttribute() const
Definition: pad.h:442
const wxString & GetPinFunction() const
Definition: pad.h:145
const wxString & GetNumber() const
Definition: pad.h:134
bool IsNoConnectPad() const
Definition: pad.cpp:256
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:193
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1873
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:1082
bool IsFreePad() const
Definition: pad.cpp:262
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:410
PAD_DRILL_SHAPE GetDrillShape() const
Definition: pad.h:424
VECTOR2I GetSolderPasteMargin(PCB_LAYER_ID aLayer) const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:1128
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:973
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:545
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:266
DISPLAY_OPTIONS m_Display
EDA_ANGLE GetArcAngleStart() const
Definition: pcb_track.cpp:1866
double GetRadius() const
Definition: pcb_track.cpp:1849
EDA_ANGLE GetAngle() const
Definition: pcb_track.cpp:1856
const VECTOR2I & GetMid() const
Definition: pcb_track.h:299
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:306
Abstract dimension API.
int GetLineThickness() const
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
double m_TrackOpacity
Opacity override for all tracks.
double m_FilledShapeOpacity
Opacity override for graphic shapes.
double m_ZoneOpacity
Opacity override for filled zone areas.
double m_ImageOpacity
Opacity override for user images.
double m_PadOpacity
Opacity override for SMD pads and PTHs.
double m_ViaOpacity
Opacity override for all types of via.
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
NET_COLOR_MODE m_NetColorMode
How to use color overrides on specific nets and netclasses.
ZONE_DISPLAY_MODE m_ZoneDisplayMode
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_group.cpp:263
wxString GetName() const
Definition: pcb_group.h:66
std::vector< PCB_SHAPE > GetShapes1() const
Definition: pcb_marker.h:138
GAL_LAYER_ID GetColorLayer() const
Definition: pcb_marker.cpp:326
VECTOR2I GetPosition() const override
Definition: pcb_marker.h:69
std::vector< PCB_SHAPE > GetShapes2() const
Definition: pcb_marker.h:139
Object to handle a bitmap image that can be inserted in a PCB.
REFERENCE_IMAGE & GetReferenceImage()
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:79
int GetWidth() const override
Definition: pcb_shape.cpp:457
bool HasSolderMask() const
Definition: pcb_shape.h:183
int GetSolderMaskExpansion() const
Definition: pcb_shape.cpp:335
virtual std::vector< VECTOR2I > GetCorners() const
Return 4 corners for a rectangle or rotated rectangle (stored as a poly).
Definition: pcb_shape.cpp:515
bool IsProxyItem() const override
Definition: pcb_shape.h:114
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:89
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:69
int GetRowSpan() const
Definition: pcb_tablecell.h:65
int GetColSpan() const
Definition: pcb_tablecell.h:62
VECTOR2I GetEnd() const
Definition: pcb_table.cpp:118
bool StrokeRows() const
Definition: pcb_table.h:86
int GetRowCount() const
Definition: pcb_table.h:106
bool StrokeColumns() const
Definition: pcb_table.h:83
bool StrokeExternal() const
Definition: pcb_table.h:53
bool StrokeHeader() const
Definition: pcb_table.h:56
PCB_TABLECELL * GetCell(int aRow, int aCol) const
Definition: pcb_table.h:131
std::vector< PCB_TABLECELL * > GetCells() const
Definition: pcb_table.h:141
int GetColCount() const
Definition: pcb_table.h:104
const STROKE_PARAMS & GetSeparatorsStroke() const
Definition: pcb_table.h:71
const STROKE_PARAMS & GetBorderStroke() const
Definition: pcb_table.h:59
int GetColWidth(int aCol) const
Definition: pcb_table.h:113
VECTOR2I GetPosition() const override
Definition: pcb_table.cpp:112
EDA_ANGLE GetOrientation() const
Definition: pcb_table.h:101
int GetRowHeight(int aRow) const
Definition: pcb_table.h:123
int GetShape() const
Definition: pcb_target.h:58
int GetWidth() const
Definition: pcb_target.h:64
int GetSize() const
Definition: pcb_target.h:61
VECTOR2I GetPosition() const override
Definition: pcb_target.h:55
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
VECTOR2I GetDrawPos() const override
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
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:623
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:186
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
Definition: pcb_text.cpp:565
EDA_ANGLE GetDrawRotation() const override
Definition: pcb_text.cpp:228
int GetSolderMaskExpansion() const
Definition: pcb_track.cpp:932
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
virtual int GetWidth() const
Definition: pcb_track.h:116
PCB_LAYER_ID BottomLayer() const
Definition: pcb_track.cpp:1184
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
Definition: pcb_track.cpp:1220
int GetWidth() const override
Definition: pcb_track.cpp:359
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pcb_track.cpp:971
PCB_LAYER_ID TopLayer() const
Definition: pcb_track.cpp:1178
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
Definition: pcb_track.cpp:608
VIATYPE GetViaType() const
Definition: pcb_track.h:403
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
Definition: pcb_track.cpp:1156
VIEWERS_DISPLAY_OPTIONS m_ViewersDisplay
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:679
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:142
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
VECTOR2I GetPosition() const
VECTOR2I GetSize() const
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
int Length() const
Return the length (this).
Definition: seg.h:333
ecoord SquaredLength() const
Definition: seg.h:338
T * GetAppSettings()
Returns a handle to the a given settings by type If the settings have already been loaded,...
const SHAPE_LINE_CHAIN ConvertToPolyline(double aAccuracy=DefaultAccuracyForPCB(), double *aEffectiveAccuracy=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
Definition: shape_arc.cpp:560
int GetRadius() const
Definition: shape_circle.h:118
const VECTOR2I GetCenter() const
Definition: shape_circle.h:123
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool IsTriangulationUpToDate() const
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const VECTOR2I & GetPosition() const
Definition: shape_rect.h:160
const VECTOR2I GetSize() const
Definition: shape_rect.h:168
int GetWidth() const
Definition: shape_rect.h:176
int GetHeight() const
Definition: shape_rect.h:184
const SEG & GetSeg() const
int GetWidth() const
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
const SHAPE_LINE_CHAIN & Vertices() const
Return the list of vertices defining this simple polygon.
Definition: shape_simple.h:124
virtual const SEG GetSegment(int aIndex) const override
Definition: shape_simple.h:174
const VECTOR2I & CPoint(int aIndex) const
Return a const reference to a given point in the polygon.
Definition: shape_simple.h:102
int PointCount() const
Return the number of points (vertices) in this polygon.
Definition: shape_simple.h:88
virtual size_t GetSegmentCount() const override
Definition: shape_simple.h:176
An abstract shape on 2D plane.
Definition: shape.h:126
Simple container to manage line stroke parameters.
Definition: stroke_params.h:79
int GetWidth() const
Definition: stroke_params.h:89
LINE_STYLE GetLineStyle() const
Definition: stroke_params.h:92
static void Stroke(const SHAPE *aShape, LINE_STYLE aLineStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aRenderSettings, const std::function< void(const VECTOR2I &a, const VECTOR2I &b)> &aStroker)
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
KIFONT::FONT * m_Font
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:385
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
const std::vector< SEG > & GetHatchLines() const
Definition: zone.h:800
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:617
SHAPE_POLY_SET * Outline()
Definition: zone.h:337
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:375
ZONE_BORDER_DISPLAY_STYLE GetHatchStyle() const
Definition: zone.h:606
@ MAGENTA
Definition: color4d.h:60
@ CYAN
Definition: color4d.h:58
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:398
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:397
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:33
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
@ FRAME_CVPCB_DISPLAY
Definition: frame_type.h:53
@ FRAME_FOOTPRINT_VIEWER
Definition: frame_type.h:45
@ FRAME_FOOTPRINT_WIZARD
Definition: frame_type.h:46
@ FRAME_FOOTPRINT_PREVIEW
Definition: frame_type.h:48
@ FRAME_FOOTPRINT_CHOOSER
Definition: frame_type.h:44
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:43
@ FRAME_PCB_DISPLAY3D
Definition: frame_type.h:47
@ FRAME_CVPCB
Definition: frame_type.h:52
a few functions useful in geometry calculations.
int GetPenSizeForNormal(int aTextSize)
Definition: gr_text.cpp:64
bool IsSolderMaskLayer(int aLayer)
Definition: layer_ids.h:590
@ LAYER_PAD_FR_NETNAMES
Additional netnames layers (not associated with a PCB layer)
Definition: layer_ids.h:165
@ LAYER_PAD_BK_NETNAMES
Definition: layer_ids.h:166
@ LAYER_PAD_NETNAMES
Definition: layer_ids.h:167
@ NETNAMES_LAYER_ID_START
Definition: layer_ids.h:157
bool IsPcbLayer(int aLayer)
Test whether a layer is a valid layer for Pcbnew.
Definition: layer_ids.h:520
int GetNetnameLayer(int aLayer)
Returns a netname layer corresponding to the given layer.
Definition: layer_ids.h:695
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
@ GAL_LAYER_ID_START
Definition: layer_ids.h:192
@ LAYER_LOCKED_ITEM_SHADOW
shadow layer for locked items
Definition: layer_ids.h:240
@ LAYER_VIA_HOLEWALLS
Definition: layer_ids.h:235
@ LAYER_CONFLICTS_SHADOW
shadow layer for items flagged conficting
Definition: layer_ids.h:242
@ LAYER_DRC_SHAPE1
Custom shape for DRC marker.
Definition: layer_ids.h:245
@ LAYER_NON_PLATEDHOLES
handle color for not plated holes (holes, not pads)
Definition: layer_ids.h:198
@ LAYER_DRC_EXCLUSION
layer for drc markers which have been individually excluded
Definition: layer_ids.h:237
@ LAYER_PCB_BACKGROUND
PCB background color.
Definition: layer_ids.h:221
@ LAYER_PADS
Meta control for all pads opacity/visibility (color ignored)
Definition: layer_ids.h:231
@ LAYER_DRC_WARNING
layer for drc markers with SEVERITY_WARNING
Definition: layer_ids.h:236
@ LAYER_PAD_PLATEDHOLES
to draw pad holes (plated)
Definition: layer_ids.h:215
@ GAL_LAYER_ID_END
Definition: layer_ids.h:268
@ LAYER_DRC_SHAPE2
Custom shape for DRC marker.
Definition: layer_ids.h:246
@ LAYER_ZONE_START
Virtual layers for stacking zones and tracks on a given copper layer.
Definition: layer_ids.h:257
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:202
@ LAYER_MARKER_SHADOWS
shadows for drc markers
Definition: layer_ids.h:238
@ LAYER_VIA_HOLES
to draw via holes (pad holes do not use this layer)
Definition: layer_ids.h:216
@ LAYER_VIA_MICROVIA
to draw micro vias
Definition: layer_ids.h:195
@ LAYER_VIA_THROUGH
to draw usual through hole vias
Definition: layer_ids.h:197
@ LAYER_DRC_ERROR
layer for drc markers with SEVERITY_ERROR
Definition: layer_ids.h:217
@ LAYER_VIA_BBLIND
to draw blind/buried vias
Definition: layer_ids.h:196
@ LAYER_PAD_HOLEWALLS
Definition: layer_ids.h:234
bool IsNetnameLayer(int aLayer)
Test whether a layer is a netname layer.
Definition: layer_ids.h:710
bool IsHoleLayer(int aLayer)
Definition: layer_ids.h:581
bool IsExternalCopperLayer(int aLayerId)
Tests whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition: layer_ids.h:542
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ Edge_Cuts
Definition: layer_ids.h:112
@ F_Paste
Definition: layer_ids.h:104
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:135
@ F_Cu
Definition: layer_ids.h:64
bool IsZoneFillLayer(int aLayer)
Definition: layer_ids.h:716
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:810
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:247
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition: padstack.h:69
Class to handle a set of BOARD_ITEMs.
PCBNEW_SETTINGS * pcbconfig()
Definition: pcb_painter.cpp:75
@ SHOW_WITH_VIA_ALWAYS
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
PGM_BASE * PgmOrNull()
similar to PGM_BASE& Pgm(), but return a reference that can be nullptr when running a shared lib from...
Definition: pgm_base.cpp:1067
see class PGM_BASE
@ SH_RECT
axis-aligned rectangle
Definition: shape.h:47
@ SH_CIRCLE
circle
Definition: shape.h:50
@ SH_SIMPLE
simple polygon
Definition: shape.h:51
@ SH_SEGMENT
line segment
Definition: shape.h:48
wxString UnescapeString(const wxString &aSource)
int PrintableCharCount(const wxString &aString)
Return the number of printable (ie: non-formatting) chars.
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
TRACK_CLEARANCE_MODE m_TrackClearance
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ 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_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:99
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:106
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition: typeinfo.h:94
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690