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