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