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