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