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  wxString netname;
914  wxString padNumber;
915 
917  padNumber = UnescapeString( aPad->GetNumber() );
918 
920  netname = UnescapeString( aPad->GetShortNetname() );
921 
923  && aPad->GetShortNetname().StartsWith( wxT( "unconnected-(" ) ) )
924  {
925  wxString pinType = aPad->GetPinType();
926 
927  if( pinType == wxT( "no_connect" ) || pinType.EndsWith( wxT( "+no_connect" ) ) )
928  netname = wxT( "x" );
929  else if( pinType == wxT( "free" ) )
930  netname = wxT( "*" );
931  }
932 
933  if( netname.IsEmpty() && padNumber.IsEmpty() )
934  return;
935 
936  EDA_RECT padBBox = aPad->GetBoundingBox();
937  VECTOR2D position = padBBox.Centre();
938  VECTOR2D padsize = VECTOR2D( padBBox.GetSize() );
939 
940  if( aPad->GetShape() != PAD_SHAPE::CUSTOM )
941  {
942  // Don't allow a 45° rotation to bloat a pad's bounding box unnecessarily
943  double limit = std::min( aPad->GetSize().x, aPad->GetSize().y ) * 1.1;
944 
945  if( padsize.x > limit && padsize.y > limit )
946  {
947  padsize.x = limit;
948  padsize.y = limit;
949  }
950  }
951 
952  double maxSize = PCB_RENDER_SETTINGS::MAX_FONT_SIZE;
953  double size = padsize.y;
954 
955  m_gal->Save();
956  m_gal->Translate( position );
957 
958  // Keep the size ratio for the font, but make it smaller
959  if( padsize.x < padsize.y )
960  {
961  m_gal->Rotate( DECIDEG2RAD( -900.0 ) );
962  size = padsize.x;
963  std::swap( padsize.x, padsize.y );
964  }
965 
966  // Font size limits
967  if( size > maxSize )
968  size = maxSize;
969 
970  // Default font settings
973  m_gal->SetFontBold( false );
974  m_gal->SetFontItalic( false );
975  m_gal->SetFontUnderlined( false );
976  m_gal->SetTextMirrored( false );
977  m_gal->SetStrokeColor( m_pcbSettings.GetColor( aPad, aLayer ) );
978  m_gal->SetIsStroke( true );
979  m_gal->SetIsFill( false );
980 
981  // We have already translated the GAL to be centered at the center of the pad's
982  // bounding box
983  VECTOR2D textpos( 0.0, 0.0 );
984 
985  // Divide the space, to display both pad numbers and netnames and set the Y text
986  // position to display 2 lines
987  if( !netname.IsEmpty() && !padNumber.IsEmpty() )
988  {
989  size = size / 2.5;
990  textpos.y = size / 1.7;
991  }
992 
993  if( !netname.IsEmpty() )
994  {
995  // approximate the size of net name text:
996  double tsize = 1.5 * padsize.x / std::max( PrintableCharCount( netname ), 1 );
997  tsize = std::min( tsize, size );
998 
999  // Use a smaller text size to handle interline, pen size...
1000  tsize *= 0.7;
1001  VECTOR2D namesize( tsize, tsize );
1002 
1003  m_gal->SetGlyphSize( namesize );
1004  m_gal->SetLineWidth( namesize.x / 12.0 );
1005  m_gal->BitmapText( netname, textpos, 0.0 );
1006  }
1007 
1008  if( !padNumber.IsEmpty() )
1009  {
1010  textpos.y = -textpos.y;
1011 
1012  // approximate the size of the pad number text:
1013  double tsize = 1.5 * padsize.x / std::max( PrintableCharCount( padNumber ), 1 );
1014  tsize = std::min( tsize, size );
1015 
1016  // Use a smaller text size to handle interline, pen size...
1017  tsize *= 0.7;
1018  tsize = std::min( tsize, size );
1019  VECTOR2D numsize( tsize, tsize );
1020 
1021  m_gal->SetGlyphSize( numsize );
1022  m_gal->SetLineWidth( numsize.x / 12.0 );
1023  m_gal->BitmapText( padNumber, textpos, 0.0 );
1024  }
1025 
1026  m_gal->Restore();
1027 
1028  return;
1029  }
1030  else if( aLayer == LAYER_PAD_HOLEWALLS )
1031  {
1032  m_gal->SetIsFill( false );
1033  m_gal->SetIsStroke( true );
1036 
1037  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
1038  int holeSize = seg->GetWidth() + m_holePlatingThickness;
1039 
1040  if( seg->GetSeg().A == seg->GetSeg().B ) // Circular hole
1041  m_gal->DrawCircle( seg->GetSeg().A, holeSize / 2 );
1042  else
1043  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, holeSize );
1044 
1045  return;
1046  }
1047 
1049  {
1050  // Outline mode
1051  m_gal->SetIsFill( false );
1052  m_gal->SetIsStroke( true );
1055  }
1056  else
1057  {
1058  // Filled mode
1059  m_gal->SetIsFill( true );
1060  m_gal->SetIsStroke( false );
1061  m_gal->SetFillColor( color );
1062  }
1063 
1064  if( aLayer == LAYER_PAD_PLATEDHOLES || aLayer == LAYER_NON_PLATEDHOLES )
1065  {
1066  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
1067 
1068  if( seg->GetSeg().A == seg->GetSeg().B ) // Circular hole
1069  m_gal->DrawCircle( seg->GetSeg().A, getDrillSize( aPad ).x / 2 );
1070  else
1071  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, seg->GetWidth() );
1072  }
1073  else
1074  {
1075  wxSize pad_size = aPad->GetSize();
1076  wxSize margin;
1077 
1078  switch( aLayer )
1079  {
1080  case F_Mask:
1081  case B_Mask:
1082  margin.x = margin.y = aPad->GetSolderMaskMargin();
1083  break;
1084 
1085  case F_Paste:
1086  case B_Paste:
1087  margin = aPad->GetSolderPasteMargin();
1088  break;
1089 
1090  default:
1091  margin.x = margin.y = 0;
1092  break;
1093  }
1094 
1095  std::unique_ptr<PAD> dummyPad;
1096  std::shared_ptr<SHAPE_COMPOUND> shapes;
1097 
1098  // Drawing components of compound shapes in outline mode produces a mess.
1099  bool simpleShapes = !m_pcbSettings.m_sketchMode[LAYER_PADS_TH];
1100 
1101  if( simpleShapes )
1102  {
1103  if( ( margin.x != margin.y && aPad->GetShape() != PAD_SHAPE::CUSTOM )
1104  || ( aPad->GetShape() == PAD_SHAPE::ROUNDRECT && ( margin.x < 0 || margin.y < 0 ) ) )
1105  {
1106  // Our algorithms below (polygon inflation in particular) can't handle differential
1107  // inflation along separate axes. So for those cases we build a dummy pad instead,
1108  // and inflate it.
1109 
1110  // Margin is added to both sides. If the total margin is larger than the pad
1111  // then don't display this layer
1112  if( pad_size.x + 2 * margin.x <= 0 || pad_size.y + 2 * margin.y <= 0 )
1113  return;
1114 
1115  dummyPad.reset( static_cast<PAD*>( aPad->Duplicate() ) );
1116  int initial_radius = dummyPad->GetRoundRectCornerRadius();
1117 
1118  dummyPad->SetSize( pad_size + margin + margin );
1119 
1120  if( dummyPad->GetShape() == PAD_SHAPE::ROUNDRECT )
1121  {
1122  // To keep the right margin around the corners, we need to modify the corner radius.
1123  // We must have only one radius correction, so use the smallest absolute margin.
1124  int radius_margin = std::max( margin.x, margin.y ); // radius_margin is < 0
1125  dummyPad->SetRoundRectCornerRadius( std::max( initial_radius + radius_margin, 0 ) );
1126  }
1127 
1128  shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>( dummyPad->GetEffectiveShape() );
1129  margin.x = margin.y = 0;
1130  }
1131  else
1132  {
1133  shapes = std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
1134  }
1135 
1136  if( aPad->GetShape() == PAD_SHAPE::CUSTOM && ( margin.x || margin.y ) )
1137  {
1138  // We can't draw as shapes because we don't know which edges are internal and which
1139  // are external (so we don't know when to apply the margin and when not to).
1140  simpleShapes = false;
1141  }
1142 
1143  for( const SHAPE* shape : shapes->Shapes() )
1144  {
1145  if( !simpleShapes )
1146  break;
1147 
1148  switch( shape->Type() )
1149  {
1150  case SH_SEGMENT:
1151  case SH_CIRCLE:
1152  case SH_RECT:
1153  case SH_SIMPLE:
1154  // OK so far
1155  break;
1156 
1157  default:
1158  // Not OK
1159  simpleShapes = false;
1160  break;
1161  }
1162  }
1163  }
1164 
1165  if( simpleShapes )
1166  {
1167  for( const SHAPE* shape : shapes->Shapes() )
1168  {
1169  switch( shape->Type() )
1170  {
1171  case SH_SEGMENT:
1172  {
1173  const SHAPE_SEGMENT* seg = (const SHAPE_SEGMENT*) shape;
1174  int effectiveWidth = seg->GetWidth() + 2 * margin.x;
1175 
1176  if( effectiveWidth > 0 )
1177  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B, effectiveWidth );
1178 
1179  break;
1180  }
1181 
1182  case SH_CIRCLE:
1183  {
1184  const SHAPE_CIRCLE* circle = (const SHAPE_CIRCLE*) shape;
1185  int effectiveRadius = circle->GetRadius() + margin.x;
1186 
1187  if( effectiveRadius > 0 )
1188  m_gal->DrawCircle( circle->GetCenter(), effectiveRadius );
1189 
1190  break;
1191  }
1192 
1193  case SH_RECT:
1194  {
1195  const SHAPE_RECT* r = (const SHAPE_RECT*) shape;
1196  VECTOR2I pos = r->GetPosition();
1197  VECTOR2I effectiveMargin = margin;
1198 
1199  if( effectiveMargin.x < 0 )
1200  {
1201  // A negative margin just produces a smaller rect.
1202  VECTOR2I effectiveSize = r->GetSize() + effectiveMargin;
1203 
1204  if( effectiveSize.x > 0 && effectiveSize.y > 0 )
1205  m_gal->DrawRectangle( pos - effectiveMargin, pos + effectiveSize );
1206  }
1207  else if( effectiveMargin.x > 0 )
1208  {
1209  // A positive margin produces a larger rect, but with rounded corners
1210  m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
1211 
1212  // Use segments to produce the margin with rounded corners
1213  m_gal->DrawSegment( pos,
1214  pos + VECTOR2I( r->GetWidth(), 0 ),
1215  effectiveMargin.x * 2 );
1216  m_gal->DrawSegment( pos + VECTOR2I( r->GetWidth(), 0 ),
1217  pos + r->GetSize(),
1218  effectiveMargin.x * 2 );
1219  m_gal->DrawSegment( pos + r->GetSize(),
1220  pos + VECTOR2I( 0, r->GetHeight() ),
1221  effectiveMargin.x * 2 );
1222  m_gal->DrawSegment( pos + VECTOR2I( 0, r->GetHeight() ),
1223  pos,
1224  effectiveMargin.x * 2 );
1225  }
1226  else
1227  {
1228  m_gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
1229  }
1230 
1231  break;
1232  }
1233 
1234  case SH_SIMPLE:
1235  {
1236  const SHAPE_SIMPLE* poly = static_cast<const SHAPE_SIMPLE*>( shape );
1237 
1238  if( margin.x < 0 ) // The poly shape must be deflated
1239  {
1240  int numSegs = GetArcToSegmentCount( -margin.x, m_maxError, 360.0 );
1241  SHAPE_POLY_SET outline;
1242  outline.NewOutline();
1243 
1244  for( int ii = 0; ii < poly->PointCount(); ++ii )
1245  outline.Append( poly->CPoint( ii ) );
1246 
1247  outline.Deflate( -margin.x, numSegs );
1248 
1249  m_gal->DrawPolygon( outline );
1250  }
1251  else
1252  {
1253  m_gal->DrawPolygon( poly->Vertices() );
1254  }
1255 
1256  // Now add on a rounded margin (using segments) if the margin > 0
1257  if( margin.x > 0 )
1258  {
1259  for( size_t ii = 0; ii < poly->GetSegmentCount(); ++ii )
1260  {
1261  SEG seg = poly->GetSegment( ii );
1262  m_gal->DrawSegment( seg.A, seg.B, margin.x * 2 );
1263  }
1264  }
1265 
1266  break;
1267  }
1268 
1269  default:
1270  // Better not get here; we already pre-flighted the shapes...
1271  break;
1272  }
1273  }
1274  }
1275  else
1276  {
1277  // This is expensive. Avoid if possible.
1278  SHAPE_POLY_SET polySet;
1279  aPad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ), margin.x,
1281  m_gal->DrawPolygon( polySet );
1282  }
1283  }
1284 
1285  constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_PADS;
1286 
1287  if( ( m_pcbSettings.m_clearanceDisplayFlags & clearanceFlags ) == clearanceFlags
1288  && ( aLayer == LAYER_PAD_FR || aLayer == LAYER_PAD_BK || aLayer == LAYER_PADS_TH ) )
1289  {
1290  /* Showing the clearance area is not obvious.
1291  * - A pad can be removed from some copper layers.
1292  * - For non copper layers, what is the clearance area?
1293  * So for copper layers, the clearance area is the shape if the pad is flashed on this
1294  * layer and the hole clearance area for other copper layers.
1295  * For other layers, use the pad shape, although one can use an other criteria,
1296  * depending on the non copper layer.
1297  */
1298  int activeLayer = m_pcbSettings.GetActiveLayer();
1299  bool flashActiveLayer = true;
1300 
1301  if( IsCopperLayer( activeLayer ) )
1302  flashActiveLayer = aPad->FlashLayer( activeLayer );
1303 
1304  if( flashActiveLayer || aPad->GetDrillSize().x )
1305  {
1307  m_gal->SetIsStroke( true );
1308  m_gal->SetIsFill( false );
1310 
1311  int clearance = aPad->GetOwnClearance( m_pcbSettings.GetActiveLayer() );
1312 
1313  if( flashActiveLayer && clearance > 0 )
1314  {
1315  auto shape = std::dynamic_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
1316 
1317  if( shape && shape->Size() == 1 && shape->Shapes()[0]->Type() == SH_SEGMENT )
1318  {
1319  const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape->Shapes()[0];
1320  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
1321  seg->GetWidth() + 2 * clearance );
1322  }
1323  else if( shape && shape->Size() == 1 && shape->Shapes()[0]->Type() == SH_CIRCLE )
1324  {
1325  const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape->Shapes()[0];
1326  m_gal->DrawCircle( circle->GetCenter(), circle->GetRadius() + clearance );
1327  }
1328  else
1329  {
1330  SHAPE_POLY_SET polySet;
1331 
1332  // Use ERROR_INSIDE because it avoids Clipper and is therefore much faster.
1333  aPad->TransformShapeWithClearanceToPolygon( polySet, ToLAYER_ID( aLayer ),
1334  clearance, m_maxError, ERROR_INSIDE );
1335  m_gal->DrawPolygon( polySet );
1336  }
1337  }
1338  else if( aPad->GetEffectiveHoleShape() && clearance > 0 )
1339  {
1340  clearance += m_holePlatingThickness;
1341 
1342  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
1343  m_gal->DrawSegment( seg->GetSeg().A, seg->GetSeg().B,
1344  seg->GetWidth() + 2 * clearance );
1345  }
1346  }
1347  }
1348 }
1349 
1350 
1351 void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
1352 {
1353  const COLOR4D& color = m_pcbSettings.GetColor( aShape, aShape->GetLayer() );
1354  bool sketch = m_pcbSettings.m_sketchGraphics;
1355  int thickness = getLineThickness( aShape->GetWidth() );
1356 
1357  if( sketch )
1358  {
1359  m_gal->SetIsFill( false );
1360  m_gal->SetIsStroke( true );
1362  }
1363 
1364  m_gal->SetFillColor( color );
1366 
1367  switch( aShape->GetShape() )
1368  {
1369  case SHAPE_T::SEGMENT:
1370  if( sketch )
1371  {
1372  m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
1373  }
1374  else
1375  {
1376  m_gal->SetIsFill( true );
1377  m_gal->SetIsStroke( false );
1378 
1379  m_gal->DrawSegment( aShape->GetStart(), aShape->GetEnd(), thickness );
1380  }
1381 
1382  break;
1383 
1384  case SHAPE_T::RECT:
1385  {
1386  std::vector<wxPoint> pts = aShape->GetRectCorners();
1387 
1388  if( sketch )
1389  {
1390  m_gal->DrawSegment( pts[0], pts[1], thickness );
1391  m_gal->DrawSegment( pts[1], pts[2], thickness );
1392  m_gal->DrawSegment( pts[2], pts[3], thickness );
1393  m_gal->DrawSegment( pts[3], pts[0], thickness );
1394  }
1395  else
1396  {
1397  m_gal->SetIsFill( true );
1398  m_gal->SetIsStroke( false );
1399 
1400  if( thickness > 0 )
1401  {
1402  m_gal->DrawSegment( pts[0], pts[1], thickness );
1403  m_gal->DrawSegment( pts[1], pts[2], thickness );
1404  m_gal->DrawSegment( pts[2], pts[3], thickness );
1405  m_gal->DrawSegment( pts[3], pts[0], thickness );
1406  }
1407 
1408  if( aShape->IsFilled() )
1409  {
1410  SHAPE_POLY_SET poly;
1411  poly.NewOutline();
1412 
1413  for( const wxPoint& pt : pts )
1414  poly.Append( pt );
1415 
1416  m_gal->DrawPolygon( poly );
1417  }
1418  }
1419 
1420  break;
1421  }
1422 
1423  case SHAPE_T::ARC:
1424  {
1425  double startAngle;
1426  double endAngle;
1427  aShape->CalcArcAngles( startAngle, endAngle );
1428 
1429  if( sketch )
1430  {
1431  m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
1432  DEG2RAD( startAngle ), DEG2RAD( endAngle ), thickness,
1433  m_maxError );
1434  }
1435  else
1436  {
1437  m_gal->SetIsFill( true );
1438  m_gal->SetIsStroke( false );
1439 
1440  m_gal->DrawArcSegment( aShape->GetCenter(), aShape->GetRadius(),
1441  DEG2RAD( startAngle ), DEG2RAD( endAngle ), thickness,
1442  m_maxError );
1443  }
1444  break;
1445  }
1446 
1447  case SHAPE_T::CIRCLE:
1448  if( sketch )
1449  {
1450  m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() - thickness / 2 );
1451  m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() + thickness / 2 );
1452  }
1453  else
1454  {
1455  m_gal->SetIsFill( aShape->IsFilled() );
1456  m_gal->SetIsStroke( thickness > 0 );
1457  m_gal->SetLineWidth( thickness );
1458 
1459  m_gal->DrawCircle( aShape->GetStart(), aShape->GetRadius() );
1460  }
1461  break;
1462 
1463  case SHAPE_T::POLY:
1464  {
1465  SHAPE_POLY_SET& shape = const_cast<PCB_SHAPE*>( aShape )->GetPolyShape();
1466  const FOOTPRINT* parentFootprint = aShape->GetParentFootprint();
1467 
1468  if( shape.OutlineCount() == 0 )
1469  break;
1470 
1471  if( parentFootprint )
1472  {
1473  m_gal->Save();
1474  m_gal->Translate( parentFootprint->GetPosition() );
1475  m_gal->Rotate( -parentFootprint->GetOrientationRadians() );
1476  }
1477 
1478  if( sketch )
1479  {
1480  for( int ii = 0; ii < shape.Outline( 0 ).SegmentCount(); ++ii )
1481  {
1482  SEG seg = shape.Outline( 0 ).Segment( ii );
1483  m_gal->DrawSegment( seg.A, seg.B, thickness );
1484  }
1485  }
1486  else
1487  {
1488  m_gal->SetIsFill( true );
1489  m_gal->SetIsStroke( false );
1490 
1491  if( thickness > 0 )
1492  {
1493  for( int ii = 0; ii < shape.Outline( 0 ).SegmentCount(); ++ii )
1494  {
1495  SEG seg = shape.Outline( 0 ).Segment( ii );
1496  m_gal->DrawSegment( seg.A, seg.B, thickness );
1497  }
1498  }
1499 
1500  if( aShape->IsFilled() )
1501  {
1502  // On Opengl, a not convex filled polygon is usually drawn by using triangles
1503  // as primitives. CacheTriangulation() can create basic triangle primitives to
1504  // draw the polygon solid shape on Opengl. GLU tessellation is much slower, so
1505  // currently we are using our tessellation.
1506  if( m_gal->IsOpenGlEngine() && !shape.IsTriangulationUpToDate() )
1507  shape.CacheTriangulation();
1508 
1509  m_gal->DrawPolygon( shape );
1510  }
1511  }
1512 
1513  if( parentFootprint )
1514  m_gal->Restore();
1515 
1516  break;
1517  }
1518 
1519  case SHAPE_T::BEZIER:
1520  if( sketch )
1521  {
1522  std::vector<VECTOR2D> output;
1523  std::vector<VECTOR2D> pointCtrl;
1524 
1525  pointCtrl.push_back( aShape->GetStart() );
1526  pointCtrl.push_back( aShape->GetBezierC1() );
1527  pointCtrl.push_back( aShape->GetBezierC2() );
1528  pointCtrl.push_back( aShape->GetEnd() );
1529 
1530  BEZIER_POLY converter( pointCtrl );
1531  converter.GetPoly( output, thickness );
1532 
1533  for( unsigned ii = 0; ii + 1 < output.size(); ++ii )
1534  m_gal->DrawSegment( output[ii], output[ii+1], thickness );
1535  }
1536  else
1537  {
1538  m_gal->SetIsFill( aShape->IsFilled() );
1539  m_gal->SetIsStroke( thickness > 0 );
1540  m_gal->SetLineWidth( thickness );
1541 
1542  // Use thickness as filter value to convert the curve to polyline when the curve
1543  // is not supported
1544  m_gal->DrawCurve( VECTOR2D( aShape->GetStart() ),
1545  VECTOR2D( aShape->GetBezierC1() ),
1546  VECTOR2D( aShape->GetBezierC2() ),
1547  VECTOR2D( aShape->GetEnd() ), thickness );
1548  }
1549 
1550  break;
1551 
1552  case SHAPE_T::LAST:
1553  break;
1554  }
1555 }
1556 
1557 
1558 void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
1559 {
1560  wxString shownText( aText->GetShownText() );
1561 
1562  if( shownText.Length() == 0 )
1563  return;
1564 
1565  const COLOR4D& color = m_pcbSettings.GetColor( aText, aText->GetLayer() );
1566  VECTOR2D position( aText->GetTextPos().x, aText->GetTextPos().y );
1567 
1569  {
1570  // Outline mode
1572  }
1573  else
1574  {
1575  // Filled mode
1577  }
1578 
1580  m_gal->SetIsFill( false );
1581  m_gal->SetIsStroke( true );
1582  m_gal->SetTextAttributes( aText );
1583  m_gal->StrokeText( shownText, position, aText->GetTextAngleRadians() );
1584 }
1585 
1586 
1587 void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer )
1588 {
1589  wxString shownText( aText->GetShownText() );
1590 
1591  if( shownText.Length() == 0 )
1592  return;
1593 
1594  const COLOR4D& color = m_pcbSettings.GetColor( aText, aLayer );
1595  VECTOR2D position( aText->GetTextPos().x, aText->GetTextPos().y );
1596 
1598  {
1599  // Outline mode
1601  }
1602  else
1603  {
1604  // Filled mode
1606  }
1607 
1609  m_gal->SetIsFill( false );
1610  m_gal->SetIsStroke( true );
1611  m_gal->SetTextAttributes( aText );
1612  m_gal->StrokeText( shownText, position, aText->GetDrawRotationRadians() );
1613 
1614  // Draw the umbilical line
1615  if( aText->IsSelected() )
1616  {
1619  m_gal->DrawLine( position, aText->GetParent()->GetPosition() );
1620  }
1621 }
1622 
1623 
1624 void PCB_PAINTER::draw( const FOOTPRINT* aFootprint, int aLayer )
1625 {
1626  if( aLayer == LAYER_ANCHOR )
1627  {
1628  const COLOR4D color = m_pcbSettings.GetColor( aFootprint, aLayer );
1629 
1630  // Keep the size and width constant, not related to the scale because the anchor
1631  // is just a marker on screen
1632  double anchorSize = 5.0 / m_gal->GetWorldScale(); // 5 pixels size
1633  double anchorThickness = 1.0 / m_gal->GetWorldScale(); // 1 pixels width
1634 
1635  // Draw anchor
1636  m_gal->SetIsFill( false );
1637  m_gal->SetIsStroke( true );
1639  m_gal->SetLineWidth( anchorThickness );
1640 
1641  VECTOR2D center = aFootprint->GetPosition();
1642  m_gal->DrawLine( center - VECTOR2D( anchorSize, 0 ), center + VECTOR2D( anchorSize, 0 ) );
1643  m_gal->DrawLine( center - VECTOR2D( 0, anchorSize ), center + VECTOR2D( 0, anchorSize ) );
1644  }
1645 }
1646 
1647 
1648 void PCB_PAINTER::draw( const PCB_GROUP* aGroup, int aLayer )
1649 {
1650  if( aLayer == LAYER_ANCHOR )
1651  {
1652  if( aGroup->IsSelected() && !( aGroup->GetParent() && aGroup->GetParent()->IsSelected() ) )
1653  {
1654  // Selected on our own; draw enclosing box
1655  }
1656  else if( aGroup->IsEntered() )
1657  {
1658  // Entered group; draw enclosing box
1659  }
1660  else
1661  {
1662  // Neither selected nor entered; draw nothing at the group level (ie: only draw
1663  // its members)
1664  return;
1665  }
1666 
1667  const COLOR4D color = m_pcbSettings.GetColor( aGroup, LAYER_ANCHOR );
1668 
1669  EDA_RECT bbox = aGroup->GetBoundingBox();
1672  wxPoint topLeft = bbox.GetPosition();
1673  wxPoint width = wxPoint( bbox.GetWidth(), 0 );
1674  wxPoint height = wxPoint( 0, bbox.GetHeight() );
1675 
1676  m_gal->DrawLine( topLeft, topLeft + width );
1677  m_gal->DrawLine( topLeft + width, topLeft + width + height );
1678  m_gal->DrawLine( topLeft + width + height, topLeft + height );
1679  m_gal->DrawLine( topLeft + height, topLeft );
1680 
1681  wxString name = aGroup->GetName();
1682 
1683  if( name.IsEmpty() )
1684  return;
1685 
1686  int ptSize = 12;
1687  int scaledSize = abs( KiROUND( m_gal->GetScreenWorldMatrix().GetScale().x * ptSize ) );
1688  int unscaledSize = Mils2iu( ptSize );
1689 
1690  // Scale by zoom a bit, but not too much
1691  int textSize = ( scaledSize + ( unscaledSize * 2 ) ) / 3;
1692  int penWidth = textSize / 10;
1693  wxPoint textOffset = wxPoint( width.x / 2, - KiROUND( textSize * 0.5 ) );
1694  wxPoint titleHeight = wxPoint( 0, KiROUND( textSize * 2.0 ) );
1695 
1696  if( PrintableCharCount( name ) * textSize < bbox.GetWidth() )
1697  {
1698  m_gal->DrawLine( topLeft, topLeft - titleHeight );
1699  m_gal->DrawLine( topLeft - titleHeight, topLeft + width - titleHeight );
1700  m_gal->DrawLine( topLeft + width - titleHeight, topLeft + width );
1701 
1702  m_gal->SetFontBold( false );
1703  m_gal->SetFontItalic( true );
1704  m_gal->SetFontUnderlined( false );
1708  m_gal->SetIsFill( false );
1709  m_gal->SetGlyphSize( VECTOR2D( textSize, textSize ) );
1710  m_gal->SetLineWidth( penWidth );
1711  m_gal->StrokeText( aGroup->GetName(), topLeft + textOffset, 0.0 );
1712  }
1713  }
1714 }
1715 
1716 
1717 void PCB_PAINTER::draw( const ZONE* aZone, int aLayer )
1718 {
1719  /*
1720  * aLayer will be the virtual zone layer (LAYER_ZONE_START, ... in GAL_LAYER_ID)
1721  * This is used for draw ordering in the GAL.
1722  * The color for the zone comes from the associated copper layer ( aLayer - LAYER_ZONE_START )
1723  * and the visibility comes from the combination of that copper layer and LAYER_ZONES
1724  */
1725  wxASSERT( IsZoneLayer( aLayer ) );
1726  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aLayer - LAYER_ZONE_START );
1727 
1728  if( !aZone->IsOnLayer( layer ) )
1729  return;
1730 
1731  COLOR4D color = m_pcbSettings.GetColor( aZone, layer );
1732  std::deque<VECTOR2D> corners;
1734 
1735  // Draw the outline
1736  const SHAPE_POLY_SET* outline = aZone->Outline();
1737 
1738  if( m_pcbSettings.m_zoneOutlines && outline && outline->OutlineCount() > 0 )
1739  {
1740  m_gal->SetStrokeColor( color.a > 0.0 ? color.WithAlpha( 1.0 ) : color );
1741  m_gal->SetIsFill( false );
1742  m_gal->SetIsStroke( true );
1744 
1745  // Draw each contour (main contour and holes)
1746 
1747  /*
1748  * m_gal->DrawPolygon( *outline );
1749  * should be enough, but currently does not work to draw holes contours in a complex
1750  * polygon so each contour is draw as a simple polygon
1751  */
1752 
1753  // Draw the main contour
1754  m_gal->DrawPolyline( outline->COutline( 0 ) );
1755 
1756  // Draw holes
1757  int holes_count = outline->HoleCount( 0 );
1758 
1759  for( int ii = 0; ii < holes_count; ++ii )
1760  m_gal->DrawPolyline( outline->CHole( 0, ii ) );
1761 
1762  // Draw hatch lines
1763  for( const SEG& hatchLine : aZone->GetHatchLines() )
1764  m_gal->DrawLine( hatchLine.A, hatchLine.B );
1765  }
1766 
1767  // Draw the filling
1768  if( displayMode == ZONE_DISPLAY_MODE::SHOW_FILLED
1770  || displayMode == ZONE_DISPLAY_MODE::SHOW_TRIANGULATION )
1771  {
1772  const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList( layer );
1773 
1774  if( polySet.OutlineCount() == 0 ) // Nothing to draw
1775  return;
1776 
1777  // Set up drawing options
1778  int outline_thickness = 0;
1779 
1780  if( aZone->GetFilledPolysUseThickness( layer ) )
1781  outline_thickness = aZone->GetMinThickness();
1782 
1784  m_gal->SetFillColor( color );
1785  m_gal->SetLineWidth( outline_thickness );
1786 
1787  if( displayMode == ZONE_DISPLAY_MODE::SHOW_FILLED )
1788  {
1789  m_gal->SetIsFill( true );
1790  m_gal->SetIsStroke( outline_thickness > 0 );
1791  }
1792  else
1793  {
1794  m_gal->SetIsFill( false );
1795  m_gal->SetIsStroke( true );
1796  }
1797 
1798  m_gal->DrawPolygon( polySet, displayMode == ZONE_DISPLAY_MODE::SHOW_TRIANGULATION );
1799  }
1800 }
1801 
1802 
1803 void PCB_PAINTER::draw( const PCB_DIMENSION_BASE* aDimension, int aLayer )
1804 {
1805  const COLOR4D& strokeColor = m_pcbSettings.GetColor( aDimension, aLayer );
1806 
1807  m_gal->SetStrokeColor( strokeColor );
1808  m_gal->SetIsFill( false );
1809  m_gal->SetIsStroke( true );
1810 
1812  {
1813  // Outline mode
1815  }
1816  else
1817  {
1818  // Filled mode
1819  m_gal->SetLineWidth( getLineThickness( aDimension->GetLineThickness() ) );
1820  }
1821 
1822  // Draw dimension shapes
1823  // TODO(JE) lift this out
1824  for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
1825  {
1826  switch( shape->Type() )
1827  {
1828  case SH_SEGMENT:
1829  {
1830  const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
1831  m_gal->DrawLine( seg.A, seg.B );
1832  break;
1833  }
1834 
1835  case SH_CIRCLE:
1836  {
1837  int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
1838  m_gal->DrawCircle( shape->Centre(), radius );
1839  break;
1840  }
1841 
1842  default:
1843  break;
1844  }
1845  }
1846 
1847  // Draw text
1848  const PCB_TEXT& text = aDimension->Text();
1849  VECTOR2D position( text.GetTextPos().x, text.GetTextPos().y );
1850 
1852  {
1853  // Outline mode
1855  }
1856  else
1857  {
1858  // Filled mode
1859  m_gal->SetLineWidth( getLineThickness( text.GetEffectiveTextPenWidth() ) );
1860  }
1861 
1863  m_gal->StrokeText( text.GetShownText(), position, text.GetTextAngleRadians() );
1864 }
1865 
1866 
1867 void PCB_PAINTER::draw( const PCB_TARGET* aTarget )
1868 {
1869  const COLOR4D& strokeColor = m_pcbSettings.GetColor( aTarget, aTarget->GetLayer() );
1870  VECTOR2D position( aTarget->GetPosition() );
1871  double size, radius;
1872 
1873  m_gal->SetLineWidth( getLineThickness( aTarget->GetWidth() ) );
1874  m_gal->SetStrokeColor( strokeColor );
1875  m_gal->SetIsFill( false );
1876  m_gal->SetIsStroke( true );
1877 
1878  m_gal->Save();
1879  m_gal->Translate( position );
1880 
1881  if( aTarget->GetShape() )
1882  {
1883  // shape x
1884  m_gal->Rotate( M_PI / 4.0 );
1885  size = 2.0 * aTarget->GetSize() / 3.0;
1886  radius = aTarget->GetSize() / 2.0;
1887  }
1888  else
1889  {
1890  // shape +
1891  size = aTarget->GetSize() / 2.0;
1892  radius = aTarget->GetSize() / 3.0;
1893  }
1894 
1895  m_gal->DrawLine( VECTOR2D( -size, 0.0 ), VECTOR2D( size, 0.0 ) );
1896  m_gal->DrawLine( VECTOR2D( 0.0, -size ), VECTOR2D( 0.0, size ) );
1897  m_gal->DrawCircle( VECTOR2D( 0.0, 0.0 ), radius );
1898 
1899  m_gal->Restore();
1900 }
1901 
1902 
1903 void PCB_PAINTER::draw( const PCB_MARKER* aMarker, int aLayer )
1904 {
1905  bool isShadow = aLayer == LAYER_MARKER_SHADOWS;
1906 
1907  // Don't paint shadows for invisible markers.
1908  // It would be nice to do this through layer dependencies but we can't do an "or" there today
1909  if( isShadow && aMarker->GetBoard()
1910  && !aMarker->GetBoard()->IsElementVisible( aMarker->GetColorLayer() ) )
1911  {
1912  return;
1913  }
1914 
1915  const_cast<PCB_MARKER*>( aMarker )->SetZoom( 1.0 / sqrt( m_gal->GetZoomFactor() ) );
1916 
1917  SHAPE_LINE_CHAIN polygon;
1918  aMarker->ShapeToPolygon( polygon );
1919 
1921  : aMarker->GetColorLayer() );
1922 
1923  m_gal->Save();
1924  m_gal->Translate( aMarker->GetPosition() );
1925 
1926  if( isShadow )
1927  {
1929  m_gal->SetIsStroke( true );
1930  m_gal->SetLineWidth( aMarker->MarkerScale() );
1931  }
1932  else
1933  {
1934  m_gal->SetFillColor( color );
1935  m_gal->SetIsFill( true );
1936  }
1937 
1938  m_gal->DrawPolygon( polygon );
1939  m_gal->Restore();
1940 }
1941 
1942 
1943 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:209
to draw micro vias
Definition: layer_ids.h:201
virtual wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:281
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:98
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:106
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:354
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:210
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:172
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:118
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:208
void CalcArcAngles(double &aStartAngle, double &aEndAngle) const
Calc arc start and end angles such that aStartAngle < aEndAngle.
Definition: eda_shape.cpp:451
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:336
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:314
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:637
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:222
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:953
to draw usual through hole vias
Definition: layer_ids.h:203
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:90
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:154
std::vector< wxPoint > GetRectCorners() const
Definition: eda_shape.cpp:981
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:112
bool IsNetCopperLayer(LAYER_NUM aLayer)
Checks if the given layer is "net copper", meaning it is eligible for net coloring.
Definition: layer_ids.h:1002
RATSNEST_MODE m_RatsnestMode
Ratsnest draw mode (all layers vs only visible layers)
int GetWidth() const
Definition: pcb_target.h:65
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:309
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:847
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:131
bool FlashLayer(int aLayer) const
Check to see whether the pad should be flashed on the specific layer.
Definition: pad.cpp:214
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:204
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:801
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:964
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:110
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:244
double GetRadius() const
Definition: pcb_track.cpp:946
const wxPoint GetPosition() const
Definition: eda_rect.h:111
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:157
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:569
const wxString & GetNumber() const
Definition: pad.h:129
Virtual layers for stacking zones and tracks on a given copper layer.
Definition: layer_ids.h:253
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 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:477
int GetHeight() const
Definition: eda_rect.h:119
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:808
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
show a marker on pads with no nets
Definition: layer_ids.h:214
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:744
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:1554
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:952
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:220
const char * name
Definition: DXF_plotter.cpp:56
to draw blind/buried vias
Definition: layer_ids.h:202
wxSize GetSolderPasteMargin() const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
Definition: pad.cpp:789
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:976
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:64
PCB background color.
Definition: layer_ids.h:227
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:221
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
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:103
void CacheTriangulation(bool aPartition=true)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
bool IsZoneLayer(LAYER_NUM aLayer)
Definition: layer_ids.h:983
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:101
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:472
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:136
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:411
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:143
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:272
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:100
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:144
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:691
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