KiCad PCB EDA Suite
pcb_painter.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013-2019 CERN
5  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <[email protected]>
8  * @author Maciej Suminski <[email protected]>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
28 #include <board.h>
29 #include <board_design_settings.h>
30 #include <pcb_track.h>
31 #include <pcb_group.h>
32 #include <footprint.h>
33 #include <pad.h>
34 #include <pcb_shape.h>
35 #include <string_utils.h>
36 #include <zone.h>
37 #include <pcb_text.h>
38 #include <pcb_marker.h>
39 #include <pcb_dimension.h>
40 #include <pcb_target.h>
41 #include <advanced_config.h>
42 #include <core/arraydim.h>
43 
44 #include <layer_ids.h>
45 #include <pcb_painter.h>
46 #include <pcb_display_options.h>
47 #include <project/net_settings.h>
49 
54 #include <geometry/shape_rect.h>
55 #include <geometry/shape_segment.h>
56 #include <geometry/shape_simple.h>
57 #include <geometry/shape_circle.h>
58 #include <bezier_curves.h>
59 
60 using namespace KIGFX;
61 
63 {
64  m_backgroundColor = COLOR4D( 0.0, 0.0, 0.0, 1.0 );
65  m_padNumbers = true;
66  m_netNamesOnPads = true;
67  m_netNamesOnTracks = true;
68  m_netNamesOnVias = true;
69  m_zoneOutlines = true;
72  m_sketchGraphics = false;
73  m_sketchText = false;
77 
78  m_trackOpacity = 1.0;
79  m_viaOpacity = 1.0;
80  m_padOpacity = 1.0;
81  m_zoneOpacity = 1.0;
82 
83  // By default everything should be displayed as filled
84  for( unsigned int i = 0; i < arrayDim( m_sketchMode ); ++i )
85  m_sketchMode[i] = false;
86 
87  update();
88 }
89 
90 
92 {
94 
95  // Init board layers colors:
96  for( int i = 0; i < PCB_LAYER_ID_COUNT; i++ )
97  {
98  m_layerColors[i] = aSettings->GetColor( i );
99 
100  // Guard: if the alpha channel is too small, the layer is not visible.
101  if( m_layerColors[i].a < 0.2 )
102  m_layerColors[i].a = 0.2;
103  }
104 
105  // Init specific graphic layers colors:
106  for( int i = GAL_LAYER_ID_START; i < GAL_LAYER_ID_END; i++ )
107  m_layerColors[i] = aSettings->GetColor( i );
108 
109  // Colors for layers that aren't theme-able
111  m_layerColors[LAYER_VIA_NETNAMES] = COLOR4D( 0.2, 0.2, 0.2, 0.9 );
112  m_layerColors[LAYER_PAD_NETNAMES] = COLOR4D( 1.0, 1.0, 1.0, 0.9 );
113  m_layerColors[LAYER_PAD_FR] = aSettings->GetColor( F_Cu );
114  m_layerColors[LAYER_PAD_BK] = aSettings->GetColor( B_Cu );
115  m_layerColors[LAYER_PAD_FR_NETNAMES] = COLOR4D( 1.0, 1.0, 1.0, 0.9 );
116  m_layerColors[LAYER_PAD_BK_NETNAMES] = COLOR4D( 1.0, 1.0, 1.0, 0.9 );
117 
118  // Netnames for copper layers
119  for( LSEQ cu = LSET::AllCuMask().CuStack(); cu; ++cu )
120  {
121  const COLOR4D lightLabel( 0.8, 0.8, 0.8, 0.7 );
122  const COLOR4D darkLabel = lightLabel.Inverted();
123  PCB_LAYER_ID layer = *cu;
124 
125  if( m_layerColors[layer].GetBrightness() > 0.5 )
126  m_layerColors[GetNetnameLayer( layer )] = darkLabel;
127  else
128  m_layerColors[GetNetnameLayer( layer )] = lightLabel;
129  }
130 
131  update();
132 }
133 
134 
136  bool aShowPageLimits )
137 {
140  m_padNumbers = aOptions.m_DisplayPadNum;
142  m_sketchText = !aOptions.m_DisplayTextFill;
145 
146  // Whether to draw tracks, vias & pads filled or as outlines
152 
153  // Net names display settings
154  switch( aOptions.m_DisplayNetNamesMode )
155  {
156  case 0:
157  m_netNamesOnPads = false;
158  m_netNamesOnTracks = false;
159  m_netNamesOnVias = false;
160  break;
161 
162  case 1:
163  m_netNamesOnPads = true;
164  m_netNamesOnTracks = false;
165  m_netNamesOnVias = true; // Follow pads or tracks? For now we chose pads....
166  break;
167 
168  case 2:
169  m_netNamesOnPads = false;
170  m_netNamesOnTracks = true;
171  m_netNamesOnVias = false; // Follow pads or tracks? For now we chose pads....
172  break;
173 
174  case 3:
175  m_netNamesOnPads = true;
176  m_netNamesOnTracks = true;
177  m_netNamesOnVias = true;
178  break;
179  }
180 
181  // Zone display settings
183 
184  // Clearance settings
185  switch( aOptions.m_ShowTrackClearanceMode )
186  {
189  break;
190 
193  break;
194 
197  break;
198 
201  break;
202 
205  break;
206  }
207 
208  if( aOptions.m_DisplayPadClearance )
210 
212 
213  m_netColorMode = aOptions.m_NetColorMode;
214 
216 
217  m_trackOpacity = aOptions.m_TrackOpacity;
218  m_viaOpacity = aOptions.m_ViaOpacity;
219  m_padOpacity = aOptions.m_PadOpacity;
220  m_zoneOpacity = aOptions.m_ZoneOpacity;
221 
222  m_showPageLimits = aShowPageLimits;
223 }
224 
225 
226 COLOR4D PCB_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const
227 {
228  const EDA_ITEM* item = dynamic_cast<const EDA_ITEM*>( aItem );
229  const BOARD_CONNECTED_ITEM* conItem = dynamic_cast<const BOARD_CONNECTED_ITEM*> ( aItem );
230  int netCode = -1;
231  int originalLayer = aLayer;
232 
233  // Marker shadows
234  if( aLayer == LAYER_MARKER_SHADOWS )
235  return m_backgroundColor.WithAlpha( 0.6 );
236 
237  if( IsHoleLayer( aLayer ) && m_isPrinting )
238  {
239  // Careful that we don't end up with the same colour for the annular ring and the hole
240  // when printing in B&W.
241  const PAD* pad = dynamic_cast<const PAD*>( item );
242  const PCB_VIA* via = dynamic_cast<const PCB_VIA*>( item );
243  int holeLayer = aLayer;
244  int annularRingLayer = UNDEFINED_LAYER;
245 
246  if( pad && pad->GetAttribute() == PAD_ATTRIB::PTH )
247  annularRingLayer = LAYER_PADS_TH;
248  else if( via && via->GetViaType() == VIATYPE::MICROVIA )
249  annularRingLayer = LAYER_VIA_MICROVIA;
250  else if( via && via->GetViaType() == VIATYPE::BLIND_BURIED )
251  annularRingLayer = LAYER_VIA_BBLIND;
252  else if( via && via->GetViaType() == VIATYPE::THROUGH )
253  annularRingLayer = LAYER_VIA_THROUGH;
254 
255  if( annularRingLayer != UNDEFINED_LAYER
256  && m_layerColors[ holeLayer ] == m_layerColors[ annularRingLayer ] )
257  {
258  aLayer = LAYER_PCB_BACKGROUND;
259  }
260  }
261 
262  // Zones should pull from the copper layer
263  if( item && ( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T ) )
264  {
265  if( IsZoneLayer( aLayer ) )
266  aLayer = aLayer - LAYER_ZONE_START;
267  }
268 
269  // Hole walls should pull from the copper layer
270  if( aLayer == LAYER_PAD_HOLEWALLS )
271  aLayer = LAYER_PADS_TH;
272  else if( aLayer == LAYER_VIA_HOLEWALLS )
273  aLayer = LAYER_VIA_THROUGH;
274 
275  // Normal path: get the layer base color
276  COLOR4D color = m_layerColors[aLayer];
277 
278  if( !item )
279  return m_layerColors[aLayer];
280 
281  // Selection disambiguation
282  if( item->IsBrightened() )
283  return color.Brightened( m_selectFactor ).WithAlpha( 0.8 );
284 
285  // Normal selection
286  if( item->IsSelected() )
287  color = m_layerColorsSel[aLayer];
288 
289  // Try to obtain the netcode for the item
290  if( conItem )
291  netCode = conItem->GetNetCode();
292 
293  bool highlighted = m_highlightEnabled && m_highlightNetcodes.count( netCode );
294  bool selected = item->IsSelected();
295 
296  // Apply net color overrides
297  if( conItem && m_netColorMode == NET_COLOR_MODE::ALL && IsNetCopperLayer( aLayer ) )
298  {
299  COLOR4D netColor = COLOR4D::UNSPECIFIED;
300 
301  auto ii = m_netColors.find( netCode );
302 
303  if( ii != m_netColors.end() )
304  netColor = ii->second;
305 
306  if( netColor == COLOR4D::UNSPECIFIED )
307  {
308  auto jj = m_netclassColors.find( conItem->GetNetClassName() );
309 
310  if( jj != m_netclassColors.end() )
311  netColor = jj->second;
312  }
313 
314  if( netColor == COLOR4D::UNSPECIFIED )
315  netColor = color;
316 
317  if( selected )
318  {
319  // Selection brightening overrides highlighting
320  netColor.Brighten( m_selectFactor );
321  }
322  else if( m_highlightEnabled )
323  {
324  // Highlight brightens objects on all layers and darkens everything else for contrast
325  if( highlighted )
326  netColor.Brighten( m_highlightFactor );
327  else
328  netColor.Darken( 1.0 - m_highlightFactor );
329  }
330 
331  color = netColor;
332  }
333  else if( !selected && m_highlightEnabled )
334  {
335  // Single net highlight mode
336  color = m_highlightNetcodes.count( netCode ) ? m_layerColorsHi[aLayer]
337  : m_layerColorsDark[aLayer];
338  }
339 
340  // Apply high-contrast dimming
341  if( m_hiContrastEnabled && m_highContrastLayers.size() && !highlighted && !selected )
342  {
344  bool isActive = m_highContrastLayers.count( aLayer );
345 
346  switch( originalLayer )
347  {
348  case LAYER_PADS_TH:
349  if( !static_cast<const PAD*>( item )->FlashLayer( primary ) )
350  isActive = false;
351 
352  break;
353 
354  case LAYER_VIA_BBLIND:
355  case LAYER_VIA_MICROVIA:
356  // Target graphic is active if the via crosses the primary layer
357  if( static_cast<const PCB_VIA*>( item )->GetLayerSet().test( primary ) == 0 )
358  isActive = false;
359 
360  break;
361 
362  case LAYER_VIA_THROUGH:
363  if( !static_cast<const PCB_VIA*>( item )->FlashLayer( primary ) )
364  isActive = false;
365 
366  break;
367 
369  case LAYER_PAD_HOLEWALLS:
371  // Pad holes are active is any physical layer is active
372  if( LSET::PhysicalLayersMask().test( primary ) == 0 )
373  isActive = false;
374 
375  break;
376 
377  case LAYER_VIA_HOLES:
378  case LAYER_VIA_HOLEWALLS:
379  if( static_cast<const PCB_VIA*>( item )->GetViaType() == VIATYPE::BLIND_BURIED
380  || static_cast<const PCB_VIA*>( item )->GetViaType() == VIATYPE::MICROVIA )
381  {
382  // A blind or micro via's hole is active if it crosses the primary layer
383  if( static_cast<const PCB_VIA*>( item )->GetLayerSet().test( primary ) == 0 )
384  isActive = false;
385  }
386  else
387  {
388  // A through via's hole is active if any physical layer is active
389  if( LSET::PhysicalLayersMask().test( primary ) == 0 )
390  isActive = false;
391  }
392 
393  break;
394 
395  default:
396  break;
397  }
398 
399  if( !isActive )
400  {
403  else
405  }
406  }
407 
408  // Apply per-type opacity overrides
409  if( item->Type() == PCB_TRACE_T || item->Type() == PCB_ARC_T )
410  color.a *= m_trackOpacity;
411  else if( item->Type() == PCB_VIA_T )
412  color.a *= m_viaOpacity;
413  else if( item->Type() == PCB_PAD_T )
414  color.a *= m_padOpacity;
415  else if( item->Type() == PCB_ZONE_T || item->Type() == PCB_FP_ZONE_T )
416  color.a *= m_zoneOpacity;
417 
418  // No special modifiers enabled
419  return color;
420 }
421 
422 
424  PAINTER( aGal ),
425  m_maxError( ARC_HIGH_DEF ),
426  m_holePlatingThickness( 0 )
427 {
428 }
429 
430 
431 int PCB_PAINTER::getLineThickness( int aActualThickness ) const
432 {
433  // if items have 0 thickness, draw them with the outline
434  // width, otherwise respect the set value (which, no matter
435  // how small will produce something)
436  if( aActualThickness == 0 )
438 
439  return aActualThickness;
440 }
441 
442 
443 int PCB_PAINTER::getDrillShape( const PAD* aPad ) const
444 {
445  return aPad->GetDrillShape();
446 }
447 
448 
450 {
451  return VECTOR2D( aPad->GetDrillSize() );
452 }
453 
454 
455 int PCB_PAINTER::getDrillSize( const PCB_VIA* aVia ) const
456 {
457  return aVia->GetDrillValue();
458 }
459 
460 
461 bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
462 {
463  const BOARD_ITEM* item = dynamic_cast<const BOARD_ITEM*>( aItem );
464 
465  if( !item )
466  return false;
467 
468  if( const BOARD* board = item->GetBoard() )
469  {
470  BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
471  m_maxError = bds.m_MaxError;
473  }
474  else
475  {
476  m_maxError = ARC_HIGH_DEF;
478  }
479 
480  // the "cast" applied in here clarifies which overloaded draw() is called
481  switch( item->Type() )
482  {
483  case PCB_TRACE_T:
484  draw( static_cast<const PCB_TRACK*>( item ), aLayer );
485  break;
486 
487  case PCB_ARC_T:
488  draw( static_cast<const PCB_ARC*>( item ), aLayer );
489  break;
490 
491  case PCB_VIA_T:
492  draw( static_cast<const PCB_VIA*>( item ), aLayer );
493  break;
494 
495  case PCB_PAD_T:
496  draw( static_cast<const PAD*>( item ), aLayer );
497  break;
498 
499  case PCB_SHAPE_T:
500  case PCB_FP_SHAPE_T:
501  draw( static_cast<const PCB_SHAPE*>( item ), aLayer );
502  break;
503 
504  case PCB_TEXT_T:
505  draw( static_cast<const PCB_TEXT*>( item ), aLayer );
506  break;
507 
508  case PCB_FP_TEXT_T:
509  draw( static_cast<const FP_TEXT*>( item ), aLayer );
510  break;
511 
512  case PCB_FOOTPRINT_T:
513  draw( static_cast<const FOOTPRINT*>( item ), aLayer );
514  break;
515 
516  case PCB_GROUP_T:
517  draw( static_cast<const PCB_GROUP*>( item ), aLayer );
518  break;
519 
520  case PCB_ZONE_T:
521  draw( static_cast<const ZONE*>( item ), aLayer );
522  break;
523 
524  case PCB_FP_ZONE_T:
525  draw( static_cast<const ZONE*>( item ), aLayer );
526  break;
527 
528  case PCB_DIM_ALIGNED_T:
529  case PCB_DIM_CENTER_T:
531  case PCB_DIM_LEADER_T:
532  draw( static_cast<const PCB_DIMENSION_BASE*>( item ), aLayer );
533  break;
534 
535  case PCB_TARGET_T:
536  draw( static_cast<const PCB_TARGET*>( item ) );
537  break;
538 
539  case PCB_MARKER_T:
540  draw( static_cast<const PCB_MARKER*>( item ), aLayer );
541  break;
542 
543  default:
544  // Painter does not know how to draw the object
545  return false;
546  }
547 
548  // Draw bounding boxes after drawing objects so they can be seen.
549  if( ADVANCED_CFG::GetCfg().m_DrawBoundingBoxes )
550  {
551  // Show bounding boxes of painted objects for debugging.
552  EDA_RECT box = item->GetBoundingBox();
553  m_gal->SetIsFill( false );
554  m_gal->SetIsStroke( true );
555 
556  if( item->Type() == PCB_FOOTPRINT_T )
557  {
558  m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
559  COLOR4D( MAGENTA ) );
560  }
561  else
562  {
563  m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
564  COLOR4D( 0.4, 0.4, 0.4, 1 ) );
565  }
566 
567  m_gal->SetLineWidth( 1 );
568  m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
569 
570  if( item->Type() == PCB_FOOTPRINT_T )
571  {
572  m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 ) :
573  COLOR4D( CYAN ) );
574 
575  const FOOTPRINT* fp = static_cast<const FOOTPRINT*>( item );
576 
577  if( fp )
578  {
579  SHAPE_POLY_SET convex = fp->GetBoundingHull();
580 
581  m_gal->DrawPolyline( convex.COutline( 0 ) );
582  }
583  }
584  }
585 
586  return true;
587 }
588 
589 
590 void PCB_PAINTER::draw( const PCB_TRACK* aTrack, int aLayer )
591 {
592  VECTOR2D start( aTrack->GetStart() );
593  VECTOR2D end( aTrack->GetEnd() );
594  int width = aTrack->GetWidth();
595  COLOR4D color = m_pcbSettings.GetColor( aTrack, aLayer );
596 
597  if( IsNetnameLayer( aLayer ) )
598  {
600  return;
601 
602  if( aTrack->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
603  return;
604 
605  VECTOR2D line = ( end - start );
606  double length = line.EuclideanNorm();
607 
608  // Check if the track is long enough to have a netname displayed
609  if( length < 10 * width )
610  return;
611 
612  const wxString& netName = UnescapeString( aTrack->GetShortNetname() );
613  double textSize = width;
614  double penWidth = width / 12.0;
615  VECTOR2D textPosition = start + line / 2.0; // center of the track
616  double textOrientation;
617 
618  if( end.y == start.y ) // horizontal
619  {
620  textOrientation = 0;
621  textPosition.y += penWidth;
622  }
623  else if( end.x == start.x ) // vertical
624  {
625  textOrientation = M_PI / 2;
626  textPosition.x += penWidth;
627  }
628  else
629  {
630  textOrientation = -atan( line.y / line.x );
631  textPosition.x += penWidth / 1.4;
632  textPosition.y += penWidth / 1.4;
633  }
634 
635 
636  m_gal->SetIsStroke( true );
637  m_gal->SetIsFill( false );
639  m_gal->SetLineWidth( penWidth );
640  m_gal->SetFontBold( false );
641  m_gal->SetFontItalic( false );
642  m_gal->SetFontUnderlined( false );
643  m_gal->SetTextMirrored( false );
644  m_gal->SetGlyphSize( VECTOR2D( textSize * 0.55, textSize * 0.55 ) );
647  m_gal->BitmapText( netName, textPosition, textOrientation );
648 
649  return;
650  }
651  else if( IsCopperLayer( aLayer ) )
652  {
653  // Draw a regular track
654  bool outline_mode = m_pcbSettings.m_sketchMode[LAYER_TRACKS];
657  m_gal->SetIsStroke( outline_mode );
658  m_gal->SetIsFill( not outline_mode );
660 
661  m_gal->DrawSegment( start, end, width );
662  }
663 
664  // Clearance lines
665  constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_EXISTING
667 
668  if( ( m_pcbSettings.m_clearanceDisplayFlags & clearanceFlags ) == clearanceFlags )
669  {
670  int clearance = aTrack->GetOwnClearance( m_pcbSettings.GetActiveLayer() );
671 
673  m_gal->SetIsFill( false );
674  m_gal->SetIsStroke( true );
676  m_gal->DrawSegment( start, end, width + clearance * 2 );
677  }
678 }
679 
680 
681 void PCB_PAINTER::draw( const PCB_ARC* aArc, int aLayer )
682 {
683  VECTOR2D center( aArc->GetCenter() );
684  int width = aArc->GetWidth();
685  COLOR4D color = m_pcbSettings.GetColor( aArc, aLayer );
686  double radius = aArc->GetRadius();
687  double start_angle = DECIDEG2RAD( aArc->GetArcAngleStart() );
688  double angle = DECIDEG2RAD( aArc->GetAngle() );
689 
690  if( IsNetnameLayer( aLayer ) )
691  {
692  // Ummm, yeah. Anyone fancy implementing text on a path?
693  return;
694  }
695  else if( IsCopperLayer( aLayer ) )
696  {
697  // Draw a regular track
698  bool outline_mode = m_pcbSettings.m_sketchMode[LAYER_TRACKS];
701  m_gal->SetIsStroke( outline_mode );
702  m_gal->SetIsFill( not outline_mode );
704 
705  m_gal->DrawArcSegment( center, radius, start_angle, start_angle + angle, width, m_maxError );
706  }
707 
708  // Clearance lines
709  constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_EXISTING
711 
712  if( ( m_pcbSettings.m_clearanceDisplayFlags & clearanceFlags ) == clearanceFlags )
713  {
714  int clearance = aArc->GetOwnClearance( m_pcbSettings.GetActiveLayer() );
715 
717  m_gal->SetIsFill( false );
718  m_gal->SetIsStroke( true );
720 
721  m_gal->DrawArcSegment( center, radius, start_angle, start_angle + angle,
722  width + clearance * 2, m_maxError );
723  }
724 
725 // Debug only: enable this code only to test the TransformArcToPolygon function
726 // and display the polygon outline created by it.
727 // arcs on F_Cu are approximated with ERROR_INSIDE, others with ERROR_OUTSIDE
728 #if 0
729  SHAPE_POLY_SET cornerBuffer;
731  TransformArcToPolygon( cornerBuffer, aArc->GetStart(), aArc->GetMid(), aArc->GetEnd(), width,
732  m_maxError, errorloc );
734  m_gal->SetIsFill( false );
735  m_gal->SetIsStroke( true );
736  m_gal->SetStrokeColor( COLOR4D( 0, 0, 1.0, 1.0 ) );
737  m_gal->DrawPolygon( cornerBuffer );
738 #endif
739 
740 // Debug only: enable this code only to test the SHAPE_ARC::ConvertToPolyline function
741 // and display the polyline created by it.
742 #if 0
743  SHAPE_ARC arc( aArc->GetCenter(), aArc->GetStart(), aArc->GetAngle() / 10.0, aArc->GetWidth() );
744  SHAPE_LINE_CHAIN arcSpine = arc.ConvertToPolyline( m_maxError );
746  m_gal->SetIsFill( false );
747  m_gal->SetIsStroke( true );
748  m_gal->SetStrokeColor( COLOR4D( 0.3, 0.2, 0.5, 1.0 ) );
749 
750  for( int idx = 1; idx < arcSpine.PointCount(); idx++ )
751  m_gal->DrawSegment( arcSpine.CPoint( idx-1 ), arcSpine.CPoint( idx ), aArc->GetWidth() );
752 #endif
753 }
754 
755 
756 void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
757 {
758  COLOR4D color = m_pcbSettings.GetColor( aVia, aLayer );
759  VECTOR2D center( aVia->GetStart() );
760 
761  if( color == COLOR4D::CLEAR )
762  return;
763 
764  // Draw description layer
765  if( IsNetnameLayer( aLayer ) )
766  {
767  VECTOR2D position( center );
768 
769  // Is anything that we can display enabled?
770  if( !m_pcbSettings.m_netNamesOnVias || aVia->GetNetname().empty() )
771  return;
772 
773  double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
774  double size = aVia->GetWidth();
775 
776  // Font size limits
777  if( size > maxSize )
778  size = maxSize;
779 
780  m_gal->Save();
781  m_gal->Translate( position );
782 
783  // Default font settings
785  m_gal->SetStrokeColor( m_pcbSettings.GetColor( nullptr, aLayer ) );
786 
787  // Set the text position to the pad shape position (the pad position is not the best place)
788  VECTOR2D textpos( 0.0, 0.0 );
789 
790  wxString netname = UnescapeString( aVia->GetShortNetname() );
791 
792  // approximate the size of net name text:
793  double tsize = 1.5 * size / std::max( PrintableCharCount( netname ), 1 );
794  tsize = std::min( tsize, size );
795 
796  // Use a smaller text size to handle interline, pen size..
797  tsize *= 0.7;
798  VECTOR2D namesize( tsize, tsize );
799 
800  m_gal->SetGlyphSize( namesize );
801  m_gal->SetLineWidth( namesize.x / 12.0 );
802  m_gal->BitmapText( netname, textpos, 0.0 );
803 
804  m_gal->Restore();
805 
806  return;
807  }
808  else if( aLayer == LAYER_VIA_HOLEWALLS )
809  {
810  m_gal->SetIsFill( false );
811  m_gal->SetIsStroke( true );
814 
815  m_gal->DrawCircle( center, ( getDrillSize( aVia ) + m_holePlatingThickness ) / 2.0 );
816 
817  return;
818  }
819 
820  bool sketchMode = false;
821 
822  switch( aVia->GetViaType() )
823  {
827  default: wxASSERT( false ); break;
828  }
829 
830  if( sketchMode )
831  {
832  // Outline mode
833  m_gal->SetIsStroke( true );
834  m_gal->SetIsFill( false );
837  }
838  else
839  {
840  // Filled mode
841  m_gal->SetIsFill( true );
842  m_gal->SetIsStroke( false );
844  }
845 
846  if( aLayer == LAYER_VIA_HOLES )
847  {
848  m_gal->DrawCircle( center, getDrillSize( aVia ) / 2.0 );
849  }
851  {
852  m_gal->DrawCircle( center, aVia->GetWidth() / 2.0 );
853  }
854  else if( aLayer == LAYER_VIA_BBLIND || aLayer == LAYER_VIA_MICROVIA )
855  {
856  // Outer circles of blind/buried and micro-vias are drawn in a special way to indicate the
857  // top and bottom layers
858  PCB_LAYER_ID layerTop, layerBottom;
859  aVia->LayerPair( &layerTop, &layerBottom );
860 
861  double radius = aVia->GetWidth() / 2.0;
862 
863  if( !sketchMode )
864  m_gal->SetLineWidth( ( aVia->GetWidth() - aVia->GetDrillValue() ) / 2.0 );
865 
866  m_gal->DrawArc( center, radius, M_PI * -0.375, M_PI * 0.375 );
867  m_gal->DrawArc( center, radius, M_PI * 0.625, M_PI * 1.375 );
868 
869  if( sketchMode )
870  m_gal->SetStrokeColor( m_pcbSettings.GetColor( aVia, layerTop ) );
871  else
872  m_gal->SetFillColor( m_pcbSettings.GetColor( aVia, layerTop ) );
873 
874  m_gal->DrawArc( center, radius, M_PI * 1.375, M_PI * 1.625 );
875 
876  if( sketchMode )
877  m_gal->SetStrokeColor( m_pcbSettings.GetColor( aVia, layerBottom ) );
878  else
879  m_gal->SetFillColor( m_pcbSettings.GetColor( aVia, layerBottom ) );
880 
881  m_gal->DrawArc( center, radius, M_PI * 0.375, M_PI * 0.625 );
882  }
883 
884  // Clearance lines
885  constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_EXISTING | PCB_RENDER_SETTINGS::CL_VIAS;
886 
887  if( ( m_pcbSettings.m_clearanceDisplayFlags & clearanceFlags ) == clearanceFlags
888  && aLayer != LAYER_VIA_HOLES )
889  {
890  PCB_LAYER_ID activeLayer = m_pcbSettings.GetActiveLayer();
891  double radius;
892 
893  if( aVia->FlashLayer( activeLayer ) )
894  radius = aVia->GetWidth() / 2.0;
895  else
896  radius = getDrillSize( aVia ) / 2.0 + m_holePlatingThickness;
897 
899  m_gal->SetIsFill( false );
900  m_gal->SetIsStroke( true );
902  m_gal->DrawCircle( center, radius + aVia->GetOwnClearance( activeLayer ) );
903  }
904 }
905 
906 
907 void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
908 {
909  COLOR4D color = m_pcbSettings.GetColor( aPad, aLayer );
910 
911  if( IsNetnameLayer( aLayer ) )
912  {
913  // Is anything that we can display enabled?
915  {
916  bool displayNetname = ( m_pcbSettings.m_netNamesOnPads && !aPad->GetNetname().empty() );
917  EDA_RECT padBBox = aPad->GetBoundingBox();
918  VECTOR2D position = padBBox.Centre();
919  VECTOR2D padsize = VECTOR2D( padBBox.GetSize() );
920 
921  if( aPad->GetShape() != PAD_SHAPE::CUSTOM )
922  {
923  // Don't allow a 45ยบ rotation to bloat a pad's bounding box unnecessarily
924  double limit = std::min( aPad->GetSize().x, aPad->GetSize().y ) * 1.1;
925 
926  if( padsize.x > limit && padsize.y > limit )
927  {
928  padsize.x = limit;
929  padsize.y = limit;
930  }
931  }
932 
933  double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
934  double size = padsize.y;
935 
936  m_gal->Save();
937  m_gal->Translate( position );
938 
939  // Keep the size ratio for the font, but make it smaller
940  if( padsize.x < padsize.y )
941  {
942  m_gal->Rotate( DECIDEG2RAD( -900.0 ) );
943  size = padsize.x;
944  std::swap( padsize.x, padsize.y );
945  }
946 
947  // Font size limits
948  if( size > maxSize )
949  size = maxSize;
950 
951  // Default font settings
954  m_gal->SetFontBold( false );
955  m_gal->SetFontItalic( false );
956  m_gal->SetFontUnderlined( false );
957  m_gal->SetTextMirrored( false );
958  m_gal->SetStrokeColor( m_pcbSettings.GetColor( aPad, aLayer ) );
959  m_gal->SetIsStroke( true );
960  m_gal->SetIsFill( false );
961 
962  // We have already translated the GAL to be centered at the center of the pad's
963  // bounding box
964  VECTOR2D textpos( 0.0, 0.0 );
965 
966  // Divide the space, to display both pad numbers and netnames and set the Y text
967  // position to display 2 lines
968  if( displayNetname && m_pcbSettings.m_padNumbers )
969  {
970  size = size / 2.5;
971  textpos.y = size / 1.7;
972  }
973 
974  if( displayNetname )
975  {
976  wxString netname = UnescapeString( aPad->GetShortNetname() );
977  wxString pinType = aPad->GetPinType();
978 
979  // If the pad is actually not connected (unique pad in the net),
980  // shorten the displayed netname (actual name not useful)
981  // Can happen if the pad netname is edited inside the board editor, therefore
982  // having a netname not coming from schematic
983  if( netname.StartsWith( "unconnected-(" ) )
984  {
985  if( pinType == wxT( "no_connect" ) || pinType.EndsWith( wxT( "+no_connect" ) ) )
986  netname = "x";
987  else if( pinType == wxT( "free" ) )
988  netname = "*";
989  }
990 
991  // approximate the size of net name text:
992  double tsize = 1.5 * padsize.x / std::max( PrintableCharCount( netname ), 1 );
993  tsize = std::min( tsize, size );
994 
995  // Use a smaller text size to handle interline, pen size...
996  tsize *= 0.7;
997  VECTOR2D namesize( tsize, tsize );
998 
999  m_gal->SetGlyphSize( namesize );
1000  m_gal->SetLineWidth( namesize.x / 12.0 );
1001  m_gal->BitmapText( netname, textpos, 0.0 );
1002  }
1003 
1005  {
1006  const wxString& padNumber = aPad->GetNumber();
1007  textpos.y = -textpos.y;
1008 
1009  // approximate the size of the pad number text:
1010  double tsize = 1.5 * padsize.x / std::max( PrintableCharCount( padNumber ), 1 );
1011  tsize = std::min( tsize, size );
1012 
1013  // Use a smaller text size to handle interline, pen size...
1014  tsize *= 0.7;
1015  tsize = std::min( tsize, size );
1016  VECTOR2D numsize( tsize, tsize );
1017 
1018  m_gal->SetGlyphSize( numsize );
1019  m_gal->SetLineWidth( numsize.x / 12.0 );
1020  m_gal->BitmapText( padNumber, textpos, 0.0 );
1021  }
1022 
1023  m_gal->Restore();
1024  }
1025 
1026  return;
1027  }
1028  else if( aLayer == LAYER_PAD_HOLEWALLS )
1029  {
1030  m_gal->SetIsFill( false );
1031  m_gal->SetIsStroke( true );
1034 
1035  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
1036  int holeSize = seg->GetWidth() + m_holePlatingThickness;
1037 
1038  if( seg->GetSeg().A == seg->GetSeg().B ) // Circular hole
1039  m_gal->DrawCircle( seg->GetSeg().A, holeSize / 2 );
1040  else
1041  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, holeSize );
1042 
1043  return;
1044  }
1045 
1047  {
1048  // Outline mode
1049  m_gal->SetIsFill( false );
1050  m_gal->SetIsStroke( true );
1053  }
1054  else
1055  {
1056  // Filled mode
1057  m_gal->SetIsFill( true );
1058  m_gal->SetIsStroke( false );
1059  m_gal->SetFillColor( color );
1060  }
1061 
1062  if( aLayer == LAYER_PAD_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
1063  {
1064  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
1065 
1066  if( seg->GetSeg().A == seg->GetSeg().B ) // Circular hole
1067  m_gal->DrawCircle( seg->GetSeg().A, getDrillSize( aPad ).x / 2 );
1068  else
1069  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
1070  }
1071  else
1072  {
1073  wxSize pad_size = aPad->GetSize();
1074  wxSize margin;
1075 
1076  switch( aLayer )
1077  {
1078  case F_Mask:
1079  case B_Mask:
1080  margin.x = margin.y = aPad->GetSolderMaskMargin();
1081  break;
1082 
1083  case F_Paste:
1084  case B_Paste:
1085  margin = aPad->GetSolderPasteMargin();
1086  break;
1087 
1088  default:
1089  margin.x = margin.y = 0;
1090  break;
1091  }
1092 
1093  std::unique_ptr<PAD> dummyPad;
1094  std::shared_ptr<SHAPE_COMPOUND> shapes;
1095 
1096  // Drawing components of compound shapes in outline mode produces a mess.
1097  bool simpleShapes = !m_pcbSettings.m_sketchMode[LAYER_PADS_TH];
1098 
1099  if( simpleShapes )
1100  {
1101  if( ( margin.x != margin.y && aPad->GetShape() != PAD_SHAPE::CUSTOM )
1102  || ( aPad->GetShape() == PAD_SHAPE::ROUNDRECT && ( margin.x < 0 || margin.y < 0 ) ) )
1103  {
1104  // Our algorithms below (polygon inflation in particular) can't handle differential
1105  // inflation along separate axes. So for those cases we build a dummy pad instead,
1106  // and inflate it.
1107 
1108  // Margin is added to both sides. If the total margin is larger than the pad
1109  // then don't display this layer
1110  if( pad_size.x + 2 * margin.x <= 0 || pad_size.y + 2 * margin.y <= 0 )
1111  return;
1112 
1113  dummyPad.reset( static_cast<PAD*>( aPad->Duplicate() ) );
1114  int initial_radius = dummyPad->GetRoundRectCornerRadius();
1115 
1116  dummyPad->SetSize( pad_size + margin + margin );
1117 
1118  if( dummyPad->GetShape() == PAD_SHAPE::ROUNDRECT )
1119  {
1120  // To keep the right margin around the corners, we need to modify the corner radius.
1121  // We must have only one radius correction, so use the smallest absolute margin.
1122  int radius_margin = std::max( margin.x, margin.y ); // radius_margin is < 0
1123  dummyPad->SetRoundRectCornerRadius( std::max( initial_radius + radius_margin, 0 ) );
1124  }
1125 
1126  shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>( dummyPad->GetEffectiveShape() );
1127  margin.x = margin.y = 0;
1128  }
1129  else
1130  {
1131  shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
1132  }
1133 
1134  if( aPad->GetShape() == PAD_SHAPE::CUSTOM && ( margin.x || margin.y ) )
1135  {
1136  // We can't draw as shapes because we don't know which edges are internal and which
1137  // are external (so we don't know when to apply the margin and when not to).
1138  simpleShapes = false;
1139  }
1140 
1141  for( const SHAPE* shape : shapes->Shapes() )
1142  {
1143  if( !simpleShapes )
1144  break;
1145 
1146  switch( shape->Type() )
1147  {
1148  case SH_SEGMENT:
1149  case SH_CIRCLE:
1150  case SH_RECT:
1151  case SH_SIMPLE:
1152  // OK so far
1153  break;
1154 
1155  default:
1156  // Not OK
1157  simpleShapes = false;
1158  break;
1159  }
1160  }
1161  }
1162 
1163  if( simpleShapes )
1164  {
1165  for( const SHAPE* shape : shapes->Shapes() )
1166  {
1167  switch( shape->Type() )
1168  {
1169  case SH_SEGMENT:
1170  {
1171  const SHAPE_SEGMENT* seg = (const SHAPE_SEGMENT*) shape;
1172  int effectiveWidth = seg->GetWidth() + 2 * margin.x;
1173 
1174  if( effectiveWidth > 0 )
1175  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, effectiveWidth );
1176 
1177  break;
1178  }
1179 
1180  case SH_CIRCLE:
1181  {
1182  const SHAPE_CIRCLE* circle = (const SHAPE_CIRCLE*) shape;
1183  int effectiveRadius = circle->GetRadius() + margin.x;
1184 
1185  if( effectiveRadius > 0 )
1186  m_gal->DrawCircle( circle->GetCenter(), effectiveRadius );
1187 
1188  break;
1189  }
1190 
1191  case SH_RECT:
1192  {
1193  const SHAPE_RECT* r = (const SHAPE_RECT*) shape;
1194  VECTOR2I pos = r->GetPosition();
1195  VECTOR2I effectiveMargin = margin;
1196 
1197  if( effectiveMargin.x < 0 )
1198  {
1199  // A negative margin just produces a smaller rect.
1200  VECTOR2I effectiveSize = r->GetSize() + effectiveMargin;
1201 
1202  if( effectiveSize.x > 0 && effectiveSize.y > 0 )
1203  m_gal->DrawRectangle( pos - effectiveMargin, pos + effectiveSize );
1204  }
1205  else if( effectiveMargin.x > 0 )
1206  {
1207  // A positive margin produces a larger rect, but with rounded corners
1208  m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
1209 
1210  // Use segments to produce the margin with rounded corners
1211  m_gal->DrawSegment( pos,
1212  pos + VECTOR2I( r->GetWidth(), 0 ),
1213  effectiveMargin.x * 2 );
1214  m_gal->DrawSegment( pos + VECTOR2I( r->GetWidth(), 0 ),
1215  pos + r->GetSize(),
1216  effectiveMargin.x * 2 );
1217  m_gal->DrawSegment( pos + r->GetSize(),
1218  pos + VECTOR2I( 0, r->GetHeight() ),
1219  effectiveMargin.x * 2 );
1220  m_gal->DrawSegment( pos + VECTOR2I( 0, r->GetHeight() ),
1221  pos,
1222  effectiveMargin.x * 2 );
1223  }
1224  else
1225  {
1226  m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
1227  }
1228 
1229  break;
1230  }
1231 
1232  case SH_SIMPLE:
1233  {
1234  const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
1235 
1236  if( margin.x < 0 ) // The poly shape must be deflated
1237  {
1238  int numSegs = GetArcToSegmentCount( -margin.x, m_maxError, 360.0 );
1239  SHAPE_POLY_SET outline;
1240  outline.NewOutline();
1241 
1242  for( int ii = 0; ii < poly->PointCount(); ++ii )
1243  outline.Append( poly->CPoint( ii ) );
1244 
1245  outline.Deflate( -margin.x, numSegs );
1246 
1247  m_gal->DrawPolygon( outline );
1248  }
1249  else
1250  {
1251  m_gal->DrawPolygon( poly->Vertices() );
1252  }
1253 
1254  // Now add on a rounded margin (using segments) if the margin > 0
1255  if( margin.x > 0 )
1256  {
1257  for( size_t ii = 0; ii < poly->GetSegmentCount(); ++ii )
1258  {
1259  SEG seg = poly->GetSegment( ii );
1260  m_gal->DrawSegment( seg.A, seg.B, margin.x * 2 );
1261  }
1262  }
1263 
1264  break;
1265  }
1266 
1267  default:
1268  // Better not get here; we already pre-flighted the shapes...
1269  break;
1270  }
1271  }
1272  }
1273  else
1274  {
1275  // This is expensive. Avoid if possible.
1276  SHAPE_POLY_SET polySet;
1277  aPad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ), margin.x,
1279  m_gal->DrawPolygon( polySet );
1280  }
1281  }
1282 
1283  constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_PADS;
1284 
1285  if( ( m_pcbSettings.m_clearanceDisplayFlags & clearanceFlags ) == clearanceFlags
1286  && ( aLayer == LAYER_PAD_FR || aLayer == LAYER_PAD_BK || aLayer == LAYER_PADS_TH ) )
1287  {
1288  /* Showing the clearance area is not obvious.
1289  * - A pad can be removed from some copper layers.
1290  * - For non copper layers, what is the clearance area?
1291  * So for copper layers, the clearance area is the shape if the pad is flashed on this
1292  * layer and the hole clearance area for other copper layers.
1293  * For other layers, use the pad shape, although one can use an other criteria,
1294  * depending on the non copper layer.
1295  */
1296  int activeLayer = m_pcbSettings.GetActiveLayer();
1297  bool flashActiveLayer = true;
1298 
1299  if( IsCopperLayer( activeLayer ) )
1300  flashActiveLayer = aPad->FlashLayer( activeLayer );
1301 
1302  if( flashActiveLayer || aPad->GetDrillSize().x )
1303  {
1305  m_gal->SetIsStroke( true );
1306  m_gal->SetIsFill( false );
1308 
1309  int clearance = aPad->GetOwnClearance( m_pcbSettings.GetActiveLayer() );
1310 
1311  if( flashActiveLayer && clearance > 0 )
1312  {
1313  auto shape = std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
1314 
1315  if( shape && shape->Size() == 1 && shape->Shapes()[0]->Type() == SH_SEGMENT )
1316  {
1317  const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape->Shapes()[0];
1318  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
1319  seg->GetWidth() + 2 * clearance );
1320  }
1321  else if( shape && shape->Size() == 1 && shape->Shapes()[0]->Type() == SH_CIRCLE )
1322  {
1323  const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape->Shapes()[0];
1324  m_gal->DrawCircle( circle->GetCenter(), circle->GetRadius() + clearance );
1325  }
1326  else
1327  {
1328  SHAPE_POLY_SET polySet;
1329 
1330  // Use ERROR_INSIDE because it avoids Clipper and is therefore much faster.
1331  aPad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ),
1332  clearance, m_maxError, ERROR_INSIDE );
1333  m_gal->DrawPolygon( polySet );
1334  }
1335  }
1336  else if( aPad->GetEffectiveHoleShape() && clearance > 0 )
1337  {
1338  clearance += m_holePlatingThickness;
1339 
1340  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
1341  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
1342  seg->GetWidth() + 2 * clearance );
1343  }
1344  }
1345  }
1346 }
1347 
1348 
1349 void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
1350 {
1351  const COLOR4D& color = m_pcbSettings.GetColor( aShape, aShape->GetLayer() );
1352  bool sketch = m_pcbSettings.m_sketchGraphics;
1353  int thickness = getLineThickness( aShape->GetWidth() );
1354 
1355  if( sketch )
1356  {
1357  m_gal->SetIsFill( false );
1358  m_gal->SetIsStroke( true );
1360  }
1361 
1362  m_gal->SetFillColor( color );
1364 
1365  switch( aShape->GetShape() )
1366  {
1367  case SHAPE_T::SEGMENT:
1368  if( sketch )
1369  {
1370  m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
1371  }
1372  else
1373  {
1374  m_gal->SetIsFill( true );
1375  m_gal->SetIsStroke( false );
1376 
1377  m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
1378  }
1379 
1380  break;
1381 
1382  case SHAPE_T::RECT:
1383  {
1384  std::vector<wxPoint> pts = aShape->GetRectCorners();
1385 
1386  if( sketch )
1387  {
1388  m_gal->DrawSegment( pts[0], pts[1], thickness );
1389  m_gal->DrawSegment( pts[1], pts[2], thickness );
1390  m_gal->DrawSegment( pts[2], pts[3], thickness );
1391  m_gal->DrawSegment( pts[3], pts[0], thickness );
1392  }
1393  else
1394  {
1395  m_gal->SetIsFill( true );
1396  m_gal->SetIsStroke( false );
1397 
1398  if( thickness > 0 )
1399  {
1400  m_gal->DrawSegment( pts[0], pts[1], thickness );
1401  m_gal->DrawSegment( pts[1], pts[2], thickness );
1402  m_gal->DrawSegment( pts[2], pts[3], thickness );
1403  m_gal->DrawSegment( pts[3], pts[0], thickness );
1404  }
1405 
1406  if( aShape->IsFilled() )
1407  {
1408  SHAPE_POLY_SET poly;
1409  poly.NewOutline();
1410 
1411  for( const wxPoint& pt : pts )
1412  poly.Append( pt );
1413 
1414  m_gal->DrawPolygon( poly );
1415  }
1416  }
1417 
1418  break;
1419  }
1420 
1421  case SHAPE_T::ARC:
1422  {
1423  double startAngle;
1424  double endAngle;
1425  aShape->CalcArcAngles( startAngle, endAngle );
1426 
1427  if( sketch )
1428  {
1429  m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
1430  DEG2RAD( startAngle ), DEG2RAD( endAngle ), thickness,
1431  m_maxError );
1432  }
1433  else
1434  {
1435  m_gal->SetIsFill( true );
1436  m_gal->SetIsStroke( false );
1437 
1438  m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
1439  DEG2RAD( startAngle ), DEG2RAD( endAngle ), thickness,
1440  m_maxError );
1441  }
1442  break;
1443  }
1444 
1445  case SHAPE_T::CIRCLE:
1446  if( sketch )
1447  {
1448  m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() - thickness / 2 );
1449  m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() + thickness / 2 );
1450  }
1451  else
1452  {
1453  m_gal->SetIsFill( aShape->IsFilled() );
1454  m_gal->SetIsStroke( thickness > 0 );
1455  m_gal->SetLineWidth( thickness );
1456 
1457  m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() );
1458  }
1459  break;
1460 
1461  case SHAPE_T::POLY:
1462  {
1463  SHAPE_POLY_SET& shape = const_cast<PCB_SHAPE*>( aShape )->GetPolyShape();
1464  const FOOTPRINT* parentFootprint = aShape->GetParentFootprint();
1465 
1466  if( shape.OutlineCount() == 0 )
1467  break;
1468 
1469  if( parentFootprint )
1470  {
1471  m_gal->Save();
1472  m_gal->Translate( parentFootprint->GetPosition() );
1473  m_gal->Rotate( -parentFootprint->GetOrientationRadians() );
1474  }
1475 
1476  if( sketch )
1477  {
1478  for( int ii = 0; ii < shape.Outline( 0 ).SegmentCount(); ++ii )
1479  {
1480  SEG seg = shape.Outline( 0 ).Segment( ii );
1481  m_gal->DrawSegment( seg.A, seg.B, thickness );
1482  }
1483  }
1484  else
1485  {
1486  m_gal->SetIsFill( true );
1487  m_gal->SetIsStroke( false );
1488 
1489  if( thickness > 0 )
1490  {
1491  for( int ii = 0; ii < shape.Outline( 0 ).SegmentCount(); ++ii )
1492  {
1493  SEG seg = shape.Outline( 0 ).Segment( ii );
1494  m_gal->DrawSegment( seg.A, seg.B, thickness );
1495  }
1496  }
1497 
1498  if( aShape->IsFilled() )
1499  {
1500  // On Opengl, a not convex filled polygon is usually drawn by using triangles
1501  // as primitives. CacheTriangulation() can create basic triangle primitives to
1502  // draw the polygon solid shape on Opengl. GLU tessellation is much slower, so
1503  // currently we are using our tessellation.
1504  if( m_gal->IsOpenGlEngine() && !shape.IsTriangulationUpToDate() )
1505  shape.CacheTriangulation();
1506 
1507  m_gal->DrawPolygon( shape );
1508  }
1509  }
1510 
1511  if( parentFootprint )
1512  m_gal->Restore();
1513 
1514  break;
1515  }
1516 
1517  case SHAPE_T::BEZIER:
1518  if( sketch )
1519  {
1520  std::vector<VECTOR2D> output;
1521  std::vector<VECTOR2D> pointCtrl;
1522 
1523  pointCtrl.push_back( aShape->GetStart() );
1524  pointCtrl.push_back( aShape->GetBezierC1() );
1525  pointCtrl.push_back( aShape->GetBezierC2() );
1526  pointCtrl.push_back( aShape->GetEnd() );
1527 
1528  BEZIER_POLY converter( pointCtrl );
1529  converter.GetPoly( output, thickness );
1530 
1531  for( unsigned ii = 0; ii + 1 < output.size(); ++ii )
1532  m_gal->DrawSegment( output[ii], output[ii+1], thickness );
1533  }
1534  else
1535  {
1536  m_gal->SetIsFill( aShape->IsFilled() );
1537  m_gal->SetIsStroke( thickness > 0 );
1538  m_gal->SetLineWidth( thickness );
1539 
1540  // Use thickness as filter value to convert the curve to polyline when the curve
1541  // is not supported
1542  m_gal->DrawCurve( VECTOR2D( aShape->GetStart() ),
1543  VECTOR2D( aShape->GetBezierC1() ),
1544  VECTOR2D( aShape->GetBezierC2() ),
1545  VECTOR2D( aShape->GetEnd() ), thickness );
1546  }
1547 
1548  break;
1549 
1550  case SHAPE_T::LAST:
1551  break;
1552  }
1553 }
1554 
1555 
1556 void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
1557 {
1558  wxString shownText( aText->GetShownText() );
1559 
1560  if( shownText.Length() == 0 )
1561  return;
1562 
1563  const COLOR4D& color = m_pcbSettings.GetColor( aText, aText->GetLayer() );
1564  VECTOR2D position( aText->GetTextPos().x, aText->GetTextPos().y );
1565 
1567  {
1568  // Outline mode
1570  }
1571  else
1572  {
1573  // Filled mode
1575  }
1576 
1578  m_gal->SetIsFill( false );
1579  m_gal->SetIsStroke( true );
1580  m_gal->SetTextAttributes( aText );
1581  m_gal->StrokeText( shownText, position, aText->GetTextAngleRadians() );
1582 }
1583 
1584 
1585 void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer )
1586 {
1587  wxString shownText( aText->GetShownText() );
1588 
1589  if( shownText.Length() == 0 )
1590  return;
1591 
1592  const COLOR4D& color = m_pcbSettings.GetColor( aText, aLayer );
1593  VECTOR2D position( aText->GetTextPos().x, aText->GetTextPos().y );
1594 
1596  {
1597  // Outline mode
1599  }
1600  else
1601  {
1602  // Filled mode
1604  }
1605 
1607  m_gal->SetIsFill( false );
1608  m_gal->SetIsStroke( true );
1609  m_gal->SetTextAttributes( aText );
1610  m_gal->StrokeText( shownText, position, aText->GetDrawRotationRadians() );
1611 
1612  // Draw the umbilical line
1613  if( aText->IsSelected() )
1614  {
1617  m_gal->DrawLine( position, aText->GetParent()->GetPosition() );
1618  }
1619 }
1620 
1621 
1622 void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer )
1623 {
1624  if( aLayer == LAYER_ANCHOR )
1625  {
1626  const COLOR4D color = m_pcbSettings.GetColor( aFootprint, aLayer );
1627 
1628  // Keep the size and width constant, not related to the scale because the anchor
1629  // is just a marker on screen
1630  double anchorSize = 5.0 / m_gal->GetWorldScale(); // 5 pixels size
1631  double anchorThickness = 1.0 / m_gal->GetWorldScale(); // 1 pixels width
1632 
1633  // Draw anchor
1634  m_gal->SetIsFill( false );
1635  m_gal->SetIsStroke( true );
1637  m_gal->SetLineWidth( anchorThickness );
1638 
1639  VECTOR2D center = aFootprint->GetPosition();
1640  m_gal->DrawLine( center - VECTOR2D( anchorSize, 0 ), center + VECTOR2D( anchorSize, 0 ) );
1641  m_gal->DrawLine( center - VECTOR2D( 0, anchorSize ), center + VECTOR2D( 0, anchorSize ) );
1642  }
1643 }
1644 
1645 
1646 void PCB_PAINTER::draw( const PCB_GROUP* aGroup, int aLayer )
1647 {
1648  if( aLayer == LAYER_ANCHOR )
1649  {
1650  if( aGroup->IsSelected() && !( aGroup->GetParent() && aGroup->GetParent()->IsSelected() ) )
1651  {
1652  // Selected on our own; draw enclosing box
1653  }
1654  else if( aGroup->IsEntered() )
1655  {
1656  // Entered group; draw enclosing box
1657  }
1658  else
1659  {
1660  // Neither selected nor entered; draw nothing at the group level (ie: only draw
1661  // its members)
1662  return;
1663  }
1664 
1665  const COLOR4D color = m_pcbSettings.GetColor( aGroup, LAYER_ANCHOR );
1666 
1667  EDA_RECT bbox = aGroup->GetBoundingBox();
1670  wxPoint topLeft = bbox.GetPosition();
1671  wxPoint width = wxPoint( bbox.GetWidth(), 0 );
1672  wxPoint height = wxPoint( 0, bbox.GetHeight() );
1673 
1674  m_gal->DrawLine( topLeft, topLeft + width );
1675  m_gal->DrawLine( topLeft + width, topLeft + width + height );
1676  m_gal->DrawLine( topLeft + width + height, topLeft + height );
1677  m_gal->DrawLine( topLeft + height, topLeft );
1678 
1679  wxString name = aGroup->GetName();
1680 
1681  if( name.IsEmpty() )
1682  return;
1683 
1684  int ptSize = 12;
1685  int scaledSize = abs( KiROUND( m_gal->GetScreenWorldMatrix().GetScale().x * ptSize ) );
1686  int unscaledSize = Mils2iu( ptSize );
1687 
1688  // Scale by zoom a bit, but not too much
1689  int textSize = ( scaledSize + ( unscaledSize * 2 ) ) / 3;
1690  int penWidth = textSize / 10;
1691  wxPoint textOffset = wxPoint( width.x / 2, - KiROUND( textSize * 0.5 ) );
1692  wxPoint titleHeight = wxPoint( 0, KiROUND( textSize * 2.0 ) );
1693 
1694  if( PrintableCharCount( name ) * textSize < bbox.GetWidth() )
1695  {
1696  m_gal->DrawLine( topLeft, topLeft - titleHeight );
1697  m_gal->DrawLine( topLeft - titleHeight, topLeft + width - titleHeight );
1698  m_gal->DrawLine( topLeft + width - titleHeight, topLeft + width );
1699 
1700  m_gal->SetFontBold( false );
1701  m_gal->SetFontItalic( true );
1702  m_gal->SetFontUnderlined( false );
1706  m_gal->SetIsFill( false );
1707  m_gal->SetGlyphSize( VECTOR2D( textSize, textSize ) );
1708  m_gal->SetLineWidth( penWidth );
1709  m_gal->StrokeText( aGroup->GetName(), topLeft + textOffset, 0.0 );
1710  }
1711  }
1712 }
1713 
1714 
1715 void PCB_PAINTER::draw( const ZONE* aZone, int aLayer )
1716 {
1717  /*
1718  * aLayer will be the virtual zone layer (LAYER_ZONE_START, ... in GAL_LAYER_ID)
1719  * This is used for draw ordering in the GAL.
1720  * The color for the zone comes from the associated copper layer ( aLayer - LAYER_ZONE_START )
1721  * and the visibility comes from the combination of that copper layer and LAYER_ZONES
1722  */
1723  wxASSERT( IsZoneLayer( aLayer ) );
1724  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer - LAYER_ZONE_START );
1725 
1726  if( !aZone->IsOnLayer( layer ) )
1727  return;
1728 
1729  COLOR4D color = m_pcbSettings.GetColor( aZone, layer );
1730  std::deque<VECTOR2D> corners;
1732 
1733  // Draw the outline
1734  const SHAPE_POLY_SET* outline = aZone->Outline();
1735 
1736  if( m_pcbSettings.m_zoneOutlines && outline && outline->OutlineCount() > 0 )
1737  {
1738  m_gal->SetStrokeColor( color.a > 0.0 ? color.WithAlpha( 1.0 ) : color );
1739  m_gal->SetIsFill( false );
1740  m_gal->SetIsStroke( true );
1742 
1743  // Draw each contour (main contour and holes)
1744 
1745  /* This line:
1746  * m_gal->DrawPolygon( *outline );
1747  * should be enough, but currently does not work to draw holes contours in a complex polygon
1748  * so each contour is draw as a simple polygon
1749  */
1750 
1751  // Draw the main contour
1752  m_gal->DrawPolyline( outline->COutline( 0 ) );
1753 
1754  // Draw holes
1755  int holes_count = outline->HoleCount( 0 );
1756 
1757  for( int ii = 0; ii < holes_count; ++ii )
1758  m_gal->DrawPolyline( outline->CHole( 0, ii ) );
1759 
1760  // Draw hatch lines
1761  for( const SEG& hatchLine : aZone->GetHatchLines() )
1762  m_gal->DrawLine( hatchLine.A, hatchLine.B );
1763  }
1764 
1765  // Draw the filling
1766  if( displayMode == ZONE_DISPLAY_MODE::SHOW_FILLED
1768  || displayMode == ZONE_DISPLAY_MODE::SHOW_TRIANGULATION )
1769  {
1770  const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList( layer );
1771 
1772  if( polySet.OutlineCount() == 0 ) // Nothing to draw
1773  return;
1774 
1775  // Set up drawing options
1776  int outline_thickness = 0;
1777 
1778  if( aZone->GetFilledPolysUseThickness( layer ) )
1779  outline_thickness = aZone->GetMinThickness();
1780 
1782  m_gal->SetFillColor( color );
1783  m_gal->SetLineWidth( outline_thickness );
1784 
1785  if( displayMode == ZONE_DISPLAY_MODE::SHOW_FILLED )
1786  {
1787  m_gal->SetIsFill( true );
1788  m_gal->SetIsStroke( outline_thickness > 0 );
1789  }
1790  else
1791  {
1792  m_gal->SetIsFill( false );
1793  m_gal->SetIsStroke( true );
1794  }
1795 
1796  m_gal->DrawPolygon( polySet, displayMode == ZONE_DISPLAY_MODE::SHOW_TRIANGULATION );
1797  }
1798 }
1799 
1800 
1801 void PCB_PAINTER::draw( const PCB_DIMENSION_BASE* aDimension, int aLayer )
1802 {
1803  const COLOR4D& strokeColor = m_pcbSettings.GetColor( aDimension, aLayer );
1804 
1805  m_gal->SetStrokeColor( strokeColor );
1806  m_gal->SetIsFill( false );
1807  m_gal->SetIsStroke( true );
1808 
1810  {
1811  // Outline mode
1813  }
1814  else
1815  {
1816  // Filled mode
1817  m_gal->SetLineWidth( getLineThickness( aDimension->GetLineThickness() ) );
1818  }
1819 
1820  // Draw dimension shapes
1821  // TODO(JE) lift this out
1822  for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
1823  {
1824  switch( shape->Type() )
1825  {
1826  case SH_SEGMENT:
1827  {
1828  const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
1829  m_gal->DrawLine( seg.A, seg.B );
1830  break;
1831  }
1832 
1833  case SH_CIRCLE:
1834  {
1835  int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
1836  m_gal->DrawCircle( shape->Centre(), radius );
1837  break;
1838  }
1839 
1840  default:
1841  break;
1842  }
1843  }
1844 
1845  // Draw text
1846  const PCB_TEXT& text = aDimension->Text();
1847  VECTOR2D position( text.GetTextPos().x, text.GetTextPos().y );
1848 
1850  {
1851  // Outline mode
1853  }
1854  else
1855  {
1856  // Filled mode
1857  m_gal->SetLineWidth( getLineThickness( text.GetEffectiveTextPenWidth() ) );
1858  }
1859 
1861  m_gal->StrokeText( text.GetShownText(), position, text.GetTextAngleRadians() );
1862 }
1863 
1864 
1865 void PCB_PAINTER::draw( const PCB_TARGET* aTarget )
1866 {
1867  const COLOR4D& strokeColor = m_pcbSettings.GetColor( aTarget, aTarget->GetLayer() );
1868  VECTOR2D position( aTarget->GetPosition() );
1869  double size, radius;
1870 
1871  m_gal->SetLineWidth( getLineThickness( aTarget->GetWidth() ) );
1872  m_gal->SetStrokeColor( strokeColor );
1873  m_gal->SetIsFill( false );
1874  m_gal->SetIsStroke( true );
1875 
1876  m_gal->Save();
1877  m_gal->Translate( position );
1878 
1879  if( aTarget->GetShape() )
1880  {
1881  // shape x
1882  m_gal->Rotate( M_PI / 4.0 );
1883  size = 2.0 * aTarget->GetSize() / 3.0;
1884  radius = aTarget->GetSize() / 2.0;
1885  }
1886  else
1887  {
1888  // shape +
1889  size = aTarget->GetSize() / 2.0;
1890  radius = aTarget->GetSize() / 3.0;
1891  }
1892 
1893  m_gal->DrawLine( VECTOR2D( -size, 0.0 ), VECTOR2D( size, 0.0 ) );
1894  m_gal->DrawLine( VECTOR2D( 0.0, -size ), VECTOR2D( 0.0, size ) );
1895  m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), radius );
1896 
1897  m_gal->Restore();
1898 }
1899 
1900 
1901 void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
1902 {
1903  bool isShadow = aLayer == LAYER_MARKER_SHADOWS;
1904 
1905  // Don't paint shadows for invisible markers.
1906  // It would be nice to do this through layer dependencies but we can't do an "or" there today
1907  if( isShadow && aMarker->GetBoard()
1908  && !aMarker->GetBoard()->IsElementVisible( aMarker->GetColorLayer() ) )
1909  {
1910  return;
1911  }
1912 
1913  const_cast<PCB_MARKER*>( aMarker )->SetZoom( 1.0 / sqrt( m_gal->GetZoomFactor() ) );
1914 
1915  SHAPE_LINE_CHAIN polygon;
1916  aMarker->ShapeToPolygon( polygon );
1917 
1919  : aMarker->GetColorLayer() );
1920 
1921  m_gal->Save();
1922  m_gal->Translate( aMarker->GetPosition() );
1923 
1924  if( isShadow )
1925  {
1927  m_gal->SetIsStroke( true );
1928  m_gal->SetLineWidth( aMarker->MarkerScale() );
1929  }
1930  else
1931  {
1932  m_gal->SetFillColor( color );
1933  m_gal->SetIsFill( true );
1934  }
1935 
1936  m_gal->DrawPolygon( polygon );
1937  m_gal->Restore();
1938 }
1939 
1940 
1941 const double PCB_RENDER_SETTINGS::MAX_FONT_SIZE = Millimeter2iu( 10.0 );
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:759
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual const SEG GetSegment(int aIndex) const override
Definition: shape_simple.h:174
virtual void DrawPolyline(const std::deque< VECTOR2D > &aPointList)
Draw a polyline.
smd pads, front layer
Definition: layer_ids.h:198
to draw micro vias
Definition: layer_ids.h:190
virtual wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:280
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:41
int GetWidth() const
Definition: eda_shape.h:89
SHAPE_POLY_SET GetBoundingHull() const
Return a bounding polygon for the shapes and pads in the footprint.
Definition: footprint.cpp:847
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:100
virtual void LoadColors(const COLOR_SETTINGS *aSettings) override
Definition: pcb_painter.cpp:91
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:101
const VECTOR2I & CPoint(int aIndex) const
Return a const reference to a given point in the polygon.
Definition: shape_simple.h:102
double GetOrientationRadians() const
Definition: footprint.h:193
int OutlineCount() const
Return the number of vertices in a given outline/hole.
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
COLOR4D Inverted() const
Returns an inverted color, alpha remains the same.
Definition: color4d.h:333
int GetRadius() const
Definition: shape_circle.h:107
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:243
COLOR4D & Brighten(double aFactor)
Makes the color brighter by a given factor.
Definition: color4d.h:225
bool IsSelected() const
Definition: eda_item.h:122
bool FlashLayer(int aLayer) const
Checks to see whether the via should have a pad on the specific layer.
Definition: pcb_track.cpp:493
const wxPoint & GetEnd() const
Definition: pcb_track.h:105
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
marker for list end
virtual void BitmapText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle)
Draw a text using a bitmap font.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
double m_zoneOpacity
Opacity override for filled zones.
Definition: pcb_painter.h:234
COLOR4D m_layerColorsHi[LAYER_ID_COUNT]
const wxPoint & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:97
COLOR4D m_layerColors[LAYER_ID_COUNT]
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
VIATYPE GetViaType() const
Definition: pcb_track.h:352
double m_TrackOpacity
Opacity override for all tracks.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
PCB_TEXT & Text()
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Convert a Bezier curve to a polygon.
int GetSize() const
Definition: pcb_target.h:62
bool IsFlippedX() const
Return true if flip flag for the X axis is set.
virtual void SetTextAttributes(const EDA_TEXT *aText)
Loads attributes of the given text (bold/italic/underline/mirrored and so on).
int GetHolePlatingThickness() const
Pad & via drills are finish size.
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:102
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle)
Draw an arc.
bool m_sketchMode[GAL_LAYER_ID_END]
Definition: pcb_painter.h:196
SHAPE_POLY_SET * Outline()
Definition: zone.h:320
smd pads, back layer
Definition: layer_ids.h:199
int color
Definition: DXF_plotter.cpp:57
double m_ViaOpacity
Opacity override for all types of via.
Additional netnames layers (not associated with a PCB layer)
Definition: layer_ids.h:161
void SetFontBold(bool aBold)
Set bold property of current font.
Net/netclass colors are shown on all net copper.
Net/netclass colors are shown on ratsnest lines only.
int GetWidth() const
Definition: eda_rect.h:109
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:197
void CalcArcAngles(double &aStartAngle, double &aEndAngle) const
Calc arc start and end angles such that aStartAngle < aEndAngle.
Definition: eda_shape.cpp:445
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:321
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
const SHAPE_SEGMENT * GetEffectiveHoleShape() const
Return a SHAPE object representing the pad's hole.
Definition: pad.cpp:319
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:320
bool IsBrightened() const
Definition: eda_item.h:125
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
Abstract dimension API.
Definition: pcb_dimension.h:95
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:635
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
const VECTOR2I GetCenter() const
Definition: shape_circle.h:112
int GetWidth() const
Definition: pcb_track.h:102
PCB_RENDER_SETTINGS m_pcbSettings
Definition: pcb_painter.h:295
const EDA_RECT GetBoundingBox() const override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
Definition: pcb_group.cpp:223
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:76
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:265
to draw via holes (pad holes do not use this layer)
Definition: layer_ids.h:211
bool IsTriangulationUpToDate() const
virtual wxString GetNetClassName() const
Returns the netclass of the zone.
std::set< unsigned int > m_highContrastLayers
GAL * m_gal
Instance of graphic abstraction layer that gives an interface to call commands used to draw (eg.
Definition: painter.h:101
const SEG & GetSeg() const
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
int GetEffectiveTextPenWidth(int aDefaultWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultWidth.
Definition: eda_text.cpp:159
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void Rotate(double aAngle)
Rotate the context.
Ratsnest lines are drawn to items on all layers (default)
TRACE_CLEARANCE_DISPLAY_MODE_T m_ShowTrackClearanceMode
How trace clearances are displayed.
Plated through hole pad.
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
virtual VECTOR2D getDrillSize(const PAD *aPad) const
Return drill size for a pad (internal units).
int GetNetnameLayer(int aLayer)
Returns a netname layer corresponding to the given layer.
Definition: layer_ids.h:942
to draw usual through hole vias
Definition: layer_ids.h:192
std::map< wxString, KIGFX::COLOR4D > m_netclassColors
Overrides for specific net colors, stored as netcodes for the ratsnest to access easily.
Definition: pcb_painter.h:222
bool IsFilled() const
Definition: eda_shape.h:81
wxPoint GetPosition() const override
Definition: pcb_target.h:56
NET_COLOR_MODE m_netColorMode
Overrides for specific netclass colors.
Definition: pcb_painter.h:219
const wxPoint & GetBezierC1() const
Definition: eda_shape.h:145
std::vector< wxPoint > GetRectCorners() const
Definition: eda_shape.cpp:959
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:56
const wxPoint GetEnd() const
Definition: eda_rect.h:103
bool IsNetCopperLayer(LAYER_NUM aLayer)
Checks if the given layer is "net copper", meaning it is eligible for net coloring.
Definition: layer_ids.h:991
RATSNEST_MODE m_RatsnestMode
Ratsnest draw mode (all layers vs only visible layers)
int GetWidth() const
Definition: pcb_target.h:65
const wxSize & GetDrillSize() const
Definition: pad.h:243
Container for display options like enable/disable some optional drawings.
bool IsHoleLayer(LAYER_NUM aLayer)
Definition: layer_ids.h:836
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition: painter.h:57
double a
Alpha component.
Definition: color4d.h:387
const wxPoint & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:122
bool FlashLayer(int aLayer) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:213
bool IsEntered() const
Definition: eda_item.h:123
int getLineThickness(int aActualThickness) const
Get the thickness to draw for a line (e.g.
handle color for not plated holes (holes, not pads)
Definition: layer_ids.h:193
double GetDrawRotationRadians() const
Definition: fp_text.h:175
bool GetDrawIndividualViaLayers() const
Definition: pcb_painter.h:174
COLOR4D m_layerColorsDark[LAYER_ID_COUNT]
int GetMinThickness() const
Definition: zone.h:244
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth)
Draw a rounded segment.
void ResetTextAttributes()
Reset text attributes to default styling.
const std::vector< SEG > & GetHatchLines() const
Definition: zone.h:799
wxString GetShortNetname() const
VECTOR2< double > VECTOR2D
Definition: vector2d.h:621
static const double MAX_FONT_SIZE
< Maximum font size for netnames (and other dynamically shown strings)
Definition: pcb_painter.h:194
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
wxString GetName() const
Definition: pcb_group.h:65
bool m_hiContrastEnabled
Parameters for display modes.
virtual void update()
Precalculates extra colors for layers (e.g.
double GetArcAngleStart() const
Definition: pcb_track.cpp:949
int PrintableCharCount(const wxString &aString)
Return the number of printable (ie: non-formatting) chars.
Represent a set of closed polygons.
static const COLOR4D CLEAR
Definition: color4d.h:395
SHAPE_LINE_CHAIN & Outline(int aIndex)
const wxPoint GetOrigin() const
Definition: eda_rect.h:101
virtual void StrokeText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle)
Draw a vector type text using preloaded Newstroke font.
shadows for drc markers
Definition: layer_ids.h:233
double GetRadius() const
Definition: pcb_track.cpp:931
const wxPoint GetPosition() const
Definition: eda_rect.h:102
void SetBackgroundColor(const COLOR4D &aColor) override
Set the background color.
Definition: pcb_painter.h:150
const wxSize & GetSize() const
Definition: pad.h:233
wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:79
Inactive layers are shown normally (no high-contrast mode)
const wxPoint & GetBezierC2() const
Definition: eda_shape.h:148
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
const EDA_RECT GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition: pad.cpp:552
const wxString & GetNumber() const
Definition: pad.h:129
Virtual layers for stacking zones and tracks on a given copper layer.
Definition: layer_ids.h:242
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
Definition: pcb_track.cpp:434
RATSNEST_MODE m_ratsnestDisplayMode
Definition: pcb_painter.h:214
const wxString & GetPinType() const
Definition: pad.h:146
PAD_SHAPE GetShape() const
Definition: pad.h:170
const SHAPE_LINE_CHAIN & Vertices() const
Return the list of vertices defining this simple polygon.
Definition: shape_simple.h:124
Definition: color4d.h:58
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
double GetZoomFactor() const
Get the zoom factor.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:310
virtual bool IsOpenGlEngine()
Return true if the GAL engine is a OpenGL based type.
a few functions useful in geometry calculations.
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
An abstract shape on 2D plane.
Definition: shape.h:116
double m_viaOpacity
Opacity override for all types of via.
Definition: pcb_painter.h:232
void SetVerticalJustify(const EDA_TEXT_VJUSTIFY_T aVerticalJustify)
Set the vertical justify for text drawing.
void SetFontItalic(bool aItalic)
Set italic property of current font.
E_SERIE r
Definition: eserie.cpp:41
GAL_LAYER_ID GetColorLayer() const
Definition: pcb_marker.cpp:180
int NewOutline()
Creates a new hole in a given outline.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
int SegmentCount() const
Return the number of segments in this line chain.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:466
int GetHeight() const
Definition: eda_rect.h:110
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:797
wxString UnescapeString(const wxString &aSource)
circle
Definition: shape.h:46
double m_ZoneOpacity
Opacity override for filled zone areas.
void SetGlyphSize(const VECTOR2D &aSize)
Set the font glyph size.
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:104
int m_clearanceDisplayFlags
How to display nets and netclasses with color overrides.
Definition: pcb_painter.h:216
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:533
int GetSolderMaskMargin() const
Definition: pad.cpp:727
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...
Definition: seg.h:40
virtual size_t GetSegmentCount() const override
Definition: shape_simple.h:176
double GetTextAngleRadians() const
Definition: eda_text.h:198
void SetTextMirrored(bool aMirrored)
Set a mirrored property of text.
static LSET PhysicalLayersMask()
Return a mask holding all layers which are physically realized.
Definition: lset.cpp:858
int MarkerScale() const
The scaling factor to convert polygonal shape coordinates to internal units.
Definition: marker_base.h:66
COLOR4D GetColor(int aLayer) const
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aMaxError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition: pad.cpp:1530
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
Bezier curves to polygon converter.
Definition: bezier_curves.h:36
SEG Segment(int aIndex)
Return a copy of the aIndex-th segment in the line chain.
double m_trackOpacity
Opacity override for all tracks.
Definition: pcb_painter.h:231
double m_PadOpacity
Opacity override for SMD pads and PTHs.
double GetAngle() const
Definition: pcb_track.cpp:937
class PCB_MARKER, a marker used to show something
Definition: typeinfo.h:98
virtual void Restore()
Restore the context.
std::map< int, KIGFX::COLOR4D > m_netColors
Set of net codes that should not have their ratsnest displayed.
Definition: pcb_painter.h:225
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList)
Draw a polygon.
void SetFontUnderlined(bool aUnderlined)
multilayer pads, usually with holes
Definition: layer_ids.h:209
const char * name
Definition: DXF_plotter.cpp:56
to draw blind/buried vias
Definition: layer_ids.h:191
wxSize GetSolderPasteMargin() const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:772
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius)
Draw a circle using world coordinates.
FOOTPRINT * GetParentFootprint() const
Return the parent footprint or NULL if PCB_SHAPE does not belong to a footprint.
Definition: pcb_shape.cpp:123
double DEG2RAD(double deg)
Definition: trigo.h:229
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: pad.h:354
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsNetnameLayer(LAYER_NUM aLayer)
Test whether a layer is a netname layer.
Definition: layer_ids.h:965
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
COLOR4D & Darken(double aFactor)
Makes the color darker by a given factor.
Definition: color4d.h:242
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
void LoadDisplayOptions(const PCB_DISPLAY_OPTIONS &aOptions, bool aShowPageLimits)
Load settings related to display options (high-contrast mode, full or outline modes for vias/pads/tra...
Definition: layer_ids.h:71
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
virtual 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...
class ZONE, managed by a footprint
Definition: typeinfo.h:94
VECTOR2I A
Definition: seg.h:48
int PointCount() const
Return the number of points (vertices) in this polygon.
Definition: shape_simple.h:88
Handle the component boundary box.
Definition: eda_rect.h:42
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:390
double DECIDEG2RAD(double deg)
Definition: trigo.h:233
ZONE_DISPLAY_MODE m_ZoneDisplayMode
int GetShape() const
Definition: pcb_target.h:59
HIGH_CONTRAST_MODE m_contrastModeDisplay
Definition: pcb_painter.h:213
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
PCB_LAYER_ID GetActiveLayer() const
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.
wxPoint GetPosition() const override
Definition: footprint.h:187
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
wxPoint Centre() const
Definition: eda_rect.h:55
PCB background color.
Definition: layer_ids.h:216
PCB_PAINTER(GAL *aGal)
Color settings are a bit different than most of the settings objects in that there can be more than o...
double m_padOpacity
Opacity override for SMD pads and PTHs.
Definition: pcb_painter.h:233
const wxPoint & GetTextPos() const
Definition: eda_text.h:268
void TransformArcToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aStart, const wxPoint &aMid, const wxPoint &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
to draw pad holes (plated)
Definition: layer_ids.h:210
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:36
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Definition: pcb_track.cpp:166
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.h:171
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:103
void CacheTriangulation(bool aPartition=true)
bool IsZoneLayer(LAYER_NUM aLayer)
Definition: layer_ids.h:972
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
axis-aligned rectangle
Definition: shape.h:43
Inactive layers are hidden.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
SHAPE_T GetShape() const
Definition: eda_shape.h:92
virtual void Save()
Save the context.
void SetHorizontalJustify(const EDA_TEXT_HJUSTIFY_T aHorizontalJustify)
Set the horizontal justify for text drawing.
virtual const EDA_RECT GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:75
int GetRadius() const
Definition: eda_shape.cpp:466
Definition: pad.h:57
virtual int getDrillShape(const PAD *aPad) const
Return drill shape of a pad.
double GetWorldScale() const
Get the world scale.
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:135
virtual void Translate(const VECTOR2D &aTranslation)
Translate the context.
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0)
Draw a cubic bezier spline.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: fp_text.cpp:416
int GetWidth() const
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
wxPoint GetPosition() const override
Definition: pcb_marker.h:67
static constexpr int Millimeter2iu(double mm)
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:142
static const int UNCONNECTED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:372
std::set< int > m_highlightNetcodes
Definition of PCB_DISPLAY_OPTIONS class.
const wxPoint & GetMid() const
Definition: pcb_track.h:271
simple polygon
Definition: shape.h:47
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
ZONE_DISPLAY_MODE m_zoneDisplayMode
Definition: pcb_painter.h:212
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:914
int GetLineThickness() const
void draw(const PCB_TRACK *aTrack, int aLayer)
virtual void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle, double aWidth, double aMaxError)
Draw an arc segment.
const wxPoint & GetStart() const
Definition: pcb_track.h:108
COLOR4D m_layerColorsSel[LAYER_ID_COUNT]
const wxSize GetSize() const
Definition: eda_rect.h:91
NET_COLOR_MODE m_NetColorMode
How to use color overrides on specific nets and netclasses.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
line segment
Definition: shape.h:44
Abstract interface for drawing on a 2D-surface.
bool GetFilledPolysUseThickness() const
Definition: zone.h:689
Container for design settings for a BOARD object.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
VECTOR2I B
Definition: seg.h:49