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