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