KiCad PCB EDA Suite
class_pad_draw_functions.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) 2017 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
7  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
31 #include <fctsys.h>
32 #include <gr_basic.h>
33 #include <common.h>
34 #include <trigo.h>
35 #include <class_pcb_screen.h>
36 #include <class_drawpanel.h>
37 #include <drawtxt.h>
39 #include <wxBasePcbFrame.h>
40 #include <wxPcbStruct.h>
41 #include <pcbnew_id.h> // ID_TRACK_BUTT
42 #include <pcbnew.h>
43 #include <class_board.h>
45 
46 
47 
48 /* uncomment this line to show this pad with its specfic size and color
49  * when it is not on copper layers, and only one solder mask layer or solder paste layer
50  * is displayed for this pad
51  * After testing this feature,I am not sure this is a good idea
52  * but the code is left here.
53  */
54 
55 //#define SHOW_PADMASK_REAL_SIZE_AND_COLOR
56 
57 
58 // Helper class to store parameters used to draw a pad
60 {
61  m_DrawPanel = NULL;
63  m_Color = BLACK;
64  m_HoleColor = BLACK; // could be DARKGRAY;
67  m_PadClearance = 0;
68  m_Display_padnum = true;
69  m_Display_netname = true;
70  m_ShowPadFilled = true;
71  m_ShowNCMark = true;
72  m_ShowNotPlatedHole = false;
73  m_IsPrinting = false;
74 }
75 
76 
77 void D_PAD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDraw_mode,
78  const wxPoint& aOffset )
79 {
80  wxSize mask_margin; // margin (clearance) used for some non copper layers
81 
82 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
83  int showActualMaskSize = 0; /* Layer number if the actual pad size on mask layer can
84  * be displayed i.e. if only one layer is shown for this pad
85  * and this layer is a mask (solder mask or solder paste
86  */
87 #endif
88 
89  if( m_Flags & DO_NOT_DRAW )
90  return;
91 
92  PAD_DRAWINFO drawInfo;
93 
94  drawInfo.m_Offset = aOffset;
95 
96  /* We can show/hide pads from the layer manager.
97  * options are show/hide pads on front and/or back side of the board
98  * For through pads, we hide them only if both sides are hidden.
99  * smd pads on back are hidden for all layers (copper and technical layers)
100  * on back side of the board
101  * smd pads on front are hidden for all layers (copper and technical layers)
102  * on front side of the board
103  * ECO, edge and Draw layers and not considered
104  */
105 
106  BOARD* brd = GetBoard();
107 
108  auto frame = static_cast<PCB_EDIT_FRAME*> ( aPanel->GetParent() );
109  const auto& cds = frame->Settings().Colors();
110 
111  bool frontVisible = brd->IsElementVisible( LAYER_PAD_FR );
112  bool backVisible = brd->IsElementVisible( LAYER_PAD_BK );
113 
114  if( !frontVisible && !backVisible )
115  return;
116 
117  // If pad is only on front side (no layer on back side)
118  // and if hide front side pads is enabled, do not draw
119  if( !frontVisible && !( m_layerMask & LSET::BackMask() ).any() )
120  return;
121 
122  // If pad is only on back side (no layer on front side)
123  // and if hide back side pads is enabled, do not draw
124  if( !backVisible && !( m_layerMask & LSET::FrontMask() ).any() )
125  return;
126 
127 
128  wxCHECK_RET( frame != NULL, wxT( "Panel has no parent frame window." ) );
129 
130  auto displ_opts = (PCB_DISPLAY_OPTIONS*)( frame->GetDisplayOptions() );
131  PCB_SCREEN* screen = frame->GetScreen();
132 
133  if( displ_opts && displ_opts->m_DisplayPadFill == SKETCH )
134  drawInfo.m_ShowPadFilled = false;
135  else
136  drawInfo.m_ShowPadFilled = true;
137 
139 
140  if( m_layerMask[F_Cu] )
141  {
142  color = cds.GetItemColor( LAYER_PAD_FR );
143  }
144 
145  if( m_layerMask[B_Cu] )
146  {
147  color = color.LegacyMix( cds.GetItemColor( LAYER_PAD_BK ) );
148  }
149 
150  if( color == BLACK ) // Not on a visible copper layer (i.e. still nothing to show)
151  {
152  // If the pad is on only one tech layer, use the layer color else use DARKGRAY
153  LSET mask_non_copper_layers = m_layerMask & ~LSET::AllCuMask();
154 
155 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
156  mask_non_copper_layers &= brd->GetVisibleLayers();
157 #endif
158  PCB_LAYER_ID pad_layer = mask_non_copper_layers.ExtractLayer();
159 
160  switch( (int) pad_layer )
161  {
162  case UNDEFINED_LAYER: // More than one layer
163  color = DARKGRAY;
164  break;
165 
166  case UNSELECTED_LAYER: // Shouldn't really happen...
167  break;
168 
169  default:
170  color = cds.GetLayerColor( pad_layer );
171 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
172  showActualMaskSize = pad_layer;
173 #endif
174  }
175  }
176 
177  // if SMD or connector pad and high contrast mode
178  if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
180  displ_opts && displ_opts->m_ContrastModeDisplay )
181  {
182  // when routing tracks
183  if( frame->GetToolId() == ID_TRACK_BUTT )
184  {
185  PCB_LAYER_ID routeTop = screen->m_Route_Layer_TOP;
186  PCB_LAYER_ID routeBot = screen->m_Route_Layer_BOTTOM;
187 
188  // if routing between copper and component layers,
189  // or the current layer is one of said 2 external copper layers,
190  // then highlight only the current layer.
191  if( ( screen->m_Active_Layer == F_Cu || screen->m_Active_Layer == B_Cu ) ||
192  ( routeTop==F_Cu && routeBot==B_Cu ) ||
193  ( routeTop==B_Cu && routeBot==F_Cu )
194  )
195  {
196  if( !IsOnLayer( screen->m_Active_Layer ) )
197  color = COLOR4D( DARKDARKGRAY );
198  }
199  // else routing between an internal signal layer and some other
200  // layer. Grey out all PAD_ATTRIB_SMD pads not on current or the single
201  // selected external layer.
202  else if( !IsOnLayer( screen->m_Active_Layer )
203  && !IsOnLayer( routeTop )
204  && !IsOnLayer( routeBot ) )
205  {
206  color = COLOR4D( DARKDARKGRAY );
207  }
208  }
209  // when not edting tracks, show PAD_ATTRIB_SMD components not on active layer
210  // as greyed out
211  else
212  {
213  if( !IsOnLayer( screen->m_Active_Layer ) )
214  color = COLOR4D( DARKDARKGRAY );
215  }
216  }
217 
218 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
219  if( showActualMaskSize )
220  {
221  switch( showActualMaskSize )
222  {
223  case B_Mask:
224  case F_Mask:
225  mask_margin.x = mask_margin.y = GetSolderMaskMargin();
226  break;
227 
228  case B_Paste:
229  case F_Paste:
230  mask_margin = GetSolderPasteMargin();
231  break;
232 
233  default:
234  // Another layer which has no margin to handle
235  break;
236  }
237  }
238 #endif
239 
240  // if Contrast mode is ON and a technical layer active, show pads on this
241  // layer so we can see pads on paste or solder layer and the size of the
242  // mask
243  if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
244  displ_opts && displ_opts->m_ContrastModeDisplay && !IsCopperLayer( screen->m_Active_Layer ) )
245  {
246  if( IsOnLayer( screen->m_Active_Layer ) )
247  {
248  color = cds.GetLayerColor( screen->m_Active_Layer );
249 
250  // In high contrast mode, and if the active layer is the mask
251  // layer shows the pad size with the mask clearance
252  switch( screen->m_Active_Layer )
253  {
254  case B_Mask:
255  case F_Mask:
256  mask_margin.x = mask_margin.y = GetSolderMaskMargin();
257  break;
258 
259  case B_Paste:
260  case F_Paste:
261  mask_margin = GetSolderPasteMargin();
262  break;
263 
264  default:
265  break;
266  }
267  }
268  else
269  color = DARKDARKGRAY;
270  }
271 
272  if( ( aDraw_mode & GR_HIGHLIGHT ) && !( aDraw_mode & GR_AND ) )
273  color.SetToLegacyHighlightColor();
274 
275  bool DisplayIsol = displ_opts && displ_opts->m_DisplayPadIsol;
276 
277  if( !( m_layerMask & LSET::AllCuMask() ).any() )
278  DisplayIsol = false;
279 
282  {
283  drawInfo.m_ShowNotPlatedHole = true;
284  drawInfo.m_NPHoleColor = cds.GetItemColor( LAYER_NON_PLATED );
285  }
286 
287  drawInfo.m_DrawMode = aDraw_mode;
288  drawInfo.m_Color = color;
289  drawInfo.m_NoNetMarkColor = cds.GetItemColor( LAYER_NO_CONNECTS );
290  drawInfo.m_DrawPanel = aPanel;
291  drawInfo.m_Mask_margin = mask_margin;
293  drawInfo.m_IsPrinting = screen->m_IsPrinting;
294  color.a = 0.666;
295 
296  /* Get the pad clearance. This has a meaning only for Pcbnew.
297  * for CvPcb GetClearance() creates debug errors because
298  * there is no net classes so a call to GetClearance() is made only when
299  * needed (never needed in CvPcb)
300  */
301  drawInfo.m_PadClearance = DisplayIsol ? GetClearance() : 0;
302 
303  // Draw the pad number
304  if( displ_opts && !displ_opts->m_DisplayPadNum )
305  drawInfo.m_Display_padnum = false;
306 
307  if( displ_opts &&
308  (( displ_opts ->m_DisplayNetNamesMode == 0 ) || ( displ_opts->m_DisplayNetNamesMode == 2 )) )
309  drawInfo.m_Display_netname = false;
310 
311  // Display net names is restricted to pads that are on the active layer
312  // in high contrast mode display
313  if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
314  !IsOnLayer( screen->m_Active_Layer ) && displ_opts && displ_opts->m_ContrastModeDisplay )
315  drawInfo.m_Display_netname = false;
316 
317  DrawShape( aPanel->GetClipBox(), aDC, drawInfo );
318 }
319 
320 
321 void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
322 {
323  wxPoint coord[12];
324  double angle = m_Orient;
325  int seg_width;
326 
327  GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
328 
329  // calculate pad shape position :
330  wxPoint shape_pos = ShapePos() - aDrawInfo.m_Offset;
331 
332  wxSize halfsize = m_Size;
333  halfsize.x >>= 1;
334  halfsize.y >>= 1;
335 
336  switch( GetShape() )
337  {
338  case PAD_SHAPE_CIRCLE:
339  if( aDrawInfo.m_ShowPadFilled )
340  GRFilledCircle( aClipBox, aDC, shape_pos.x, shape_pos.y,
341  halfsize.x + aDrawInfo.m_Mask_margin.x, 0,
342  aDrawInfo.m_Color, aDrawInfo.m_Color );
343  else
344  GRCircle( aClipBox, aDC, shape_pos.x, shape_pos.y,
345  halfsize.x + aDrawInfo.m_Mask_margin.x,
346  m_PadSketchModePenSize, aDrawInfo.m_Color );
347 
348  if( aDrawInfo.m_PadClearance )
349  {
350  GRCircle( aClipBox,
351  aDC, shape_pos.x, shape_pos.y,
352  halfsize.x + aDrawInfo.m_PadClearance,
353  0, aDrawInfo.m_Color );
354  }
355 
356  break;
357 
358  case PAD_SHAPE_OVAL:
359  {
360  wxPoint segStart, segEnd;
361  seg_width = BuildSegmentFromOvalShape(segStart, segEnd, angle,
362  aDrawInfo.m_Mask_margin);
363  segStart += shape_pos;
364  segEnd += shape_pos;
365 
366  if( aDrawInfo.m_ShowPadFilled )
367  {
368  GRFillCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
369  seg_width, aDrawInfo.m_Color );
370  }
371  else
372  {
373  GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
374  seg_width, m_PadSketchModePenSize, aDrawInfo.m_Color );
375  }
376 
377  // Draw the clearance line
378  if( aDrawInfo.m_PadClearance )
379  {
380  seg_width += 2 * aDrawInfo.m_PadClearance;
381  GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
382  seg_width, aDrawInfo.m_Color );
383  }
384  }
385  break;
386 
387  case PAD_SHAPE_RECT:
388  case PAD_SHAPE_TRAPEZOID:
389  BuildPadPolygon( coord, aDrawInfo.m_Mask_margin, angle );
390 
391  for( int ii = 0; ii < 4; ii++ )
392  coord[ii] += shape_pos;
393 
394  GRClosedPoly( aClipBox, aDC, 4, coord, aDrawInfo.m_ShowPadFilled,
395  aDrawInfo.m_ShowPadFilled ? 0 : m_PadSketchModePenSize,
396  aDrawInfo.m_Color, aDrawInfo.m_Color );
397 
398  if( aDrawInfo.m_PadClearance )
399  {
400  #define SEGCOUNT 32 // number of segments to approximate a circle
401  SHAPE_POLY_SET outline;
403 
404  // Draw the polygon: Inflate creates only one convex polygon
405  if( outline.OutlineCount() > 0 )
406  {
407  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
408 
409  if( poly.PointCount() > 0 )
410  {
411  GRClosedPoly( aClipBox, aDC, poly.PointCount(),
412  (wxPoint*)&poly.Point( 0 ), false, 0,
413  aDrawInfo.m_Color, aDrawInfo.m_Color );
414  }
415  }
416  }
417  break;
418 
419  case PAD_SHAPE_ROUNDRECT:
420  {
421  // Use solder[Paste/Mask]size or pad size to build pad shape to draw
422  wxSize size( GetSize() );
423  size += aDrawInfo.m_Mask_margin * 2;
424  int corner_radius = GetRoundRectCornerRadius( size );
425 
426  // Draw the polygon: Inflate creates only one convex polygon
427  SHAPE_POLY_SET outline;
428  bool filled = aDrawInfo.m_ShowPadFilled;
429 
430  if( filled )
431  {
432  wxPoint centers[4];
433  GetRoundRectCornerCenters( centers, corner_radius, shape_pos,
434  size, GetOrientation() );
435  GRClosedPoly( aClipBox, aDC, 4, centers, true, corner_radius*2,
436  aDrawInfo.m_Color, aDrawInfo.m_Color );
437  }
438  else
439  {
440  TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
441  corner_radius, 64 );
442 
443  if( outline.OutlineCount() > 0 )
444  {
445  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
446 
447  if( poly.PointCount() > 0 )
448  {
449  GRClosedPoly( aClipBox, aDC, poly.PointCount(),
450  (wxPoint*)&poly.Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
451  aDrawInfo.m_Color, aDrawInfo.m_Color );
452  }
453  }
454  }
455 
456  if( aDrawInfo.m_PadClearance )
457  {
458  outline.RemoveAllContours();
459  size = GetSize();
460  size.x += aDrawInfo.m_PadClearance * 2;
461  size.y += aDrawInfo.m_PadClearance * 2;
462  corner_radius = GetRoundRectCornerRadius() + aDrawInfo.m_PadClearance;
463 
464  TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
465  corner_radius, 32 );
466 
467  if( outline.OutlineCount() > 0 )
468  {
469  // Draw the polygon: Inflate creates only one convex polygon
470  SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
471 
472  if( clearance_poly.PointCount() > 0 )
473  {
474  GRClosedPoly( aClipBox, aDC, clearance_poly.PointCount(),
475  (wxPoint*)&clearance_poly.Point( 0 ), false, 0,
476  aDrawInfo.m_Color, aDrawInfo.m_Color );
477  }
478  }
479  }
480  }
481  break;
482 
483  case PAD_SHAPE_CUSTOM:
484  {
485  // The full shape has 2 items
486  // 1- The anchor pad: a round or rect pad located at pad position
487  // 2- The custom complex shape
488  // Note: The anchor pad shape is containing by the custom complex shape polygon
489  // The anchor pad is shown to help user to see where is the anchor, only in sketch mode
490  // (In filled mode, it is merged with the basic shapes)
491  wxPoint pad_pos = GetPosition() - aDrawInfo.m_Offset;
492 
493  // In sketch mode only: Draw the anchor pad: a round or rect pad
494  if( !aDrawInfo.m_ShowPadFilled )
495  {
497  {
498  wxPoint poly[4];
499  poly[0] = wxPoint( - halfsize.x, - halfsize.y );
500  poly[1] = wxPoint( - halfsize.x, + halfsize.y );
501  poly[2] = wxPoint( + halfsize.x, + halfsize.y );
502  poly[3] = wxPoint( + halfsize.x, - halfsize.y );
503 
504  for( int ii = 0; ii < 4; ++ii )
505  {
506  RotatePoint( &poly[ii], m_Orient );
507  poly[ii] += pad_pos;
508  }
509 
510  GRClosedPoly( aClipBox, aDC, 4, poly, false, 0,
511  aDrawInfo.m_Color, aDrawInfo.m_Color );
512  }
513  else
514  {
515  GRCircle( aClipBox, aDC, pad_pos.x, pad_pos.y,
516  halfsize.x,
517  m_PadSketchModePenSize, aDrawInfo.m_Color );
518  }
519  }
520 
521  SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
522  outline.Append( m_customShapeAsPolygon );
523  CustomShapeAsPolygonToBoardPosition( &outline, pad_pos, GetOrientation() );
524  SHAPE_LINE_CHAIN* poly;
525 
526  const int segmentToCircleCount = 32;
527 
528  if( aDrawInfo.m_Mask_margin.x )
529  {
530  SHAPE_POLY_SET clearance_outline;
531  clearance_outline.Append( outline );
532  clearance_outline.Inflate( aDrawInfo.m_Mask_margin.x, segmentToCircleCount );
533 
534  poly = &clearance_outline.Outline( 0 );
535  }
536  else
537  {
538  // Draw the polygon: only one polygon is expected
539  // However we provide a multi polygon shape drawing
540  // ( for the future or to show a non expected shape )
541  for( int jj = 0; jj < outline.OutlineCount(); ++jj )
542  {
543  poly = &outline.Outline( jj );
544 
545  GRClosedPoly( aClipBox, aDC, poly->PointCount(),
546  (wxPoint*)&poly->Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
547  aDrawInfo.m_Color, aDrawInfo.m_Color );
548  }
549  }
550 
551  if( aDrawInfo.m_PadClearance )
552  {
553  SHAPE_POLY_SET clearance_outline;
554  clearance_outline.Append( outline );
555 
556  clearance_outline.Inflate( aDrawInfo.m_PadClearance, segmentToCircleCount );
557 
558  for( int jj = 0; jj < clearance_outline.OutlineCount(); ++jj )
559  {
560  poly = &clearance_outline.Outline( jj );
561 
562  if( poly->PointCount() > 0 )
563  {
564  GRClosedPoly( aClipBox, aDC, poly->PointCount(),
565  (wxPoint*)&poly->Point( 0 ), false, 0,
566  aDrawInfo.m_Color, aDrawInfo.m_Color );
567  }
568  }
569  }
570  break;
571  }
572 
573  default:
574  break;
575  }
576 
577  // Draw the pad hole
578  wxPoint holepos = m_Pos - aDrawInfo.m_Offset;
579  int hole = m_Drill.x >> 1;
580 
581  bool drawhole = hole > 0;
582 
583  if( !aDrawInfo.m_ShowPadFilled && !aDrawInfo.m_ShowNotPlatedHole )
584  drawhole = false;
585 
586  if( drawhole )
587  {
588  bool blackpenstate = false;
589 
590  if( aDrawInfo.m_IsPrinting )
591  {
592  blackpenstate = GetGRForceBlackPenState();
593  GRForceBlackPen( false );
594  aDrawInfo.m_HoleColor = WHITE;
595  aDrawInfo.m_NPHoleColor = WHITE;
596  }
597  else
598  {
599  GRSetDrawMode( aDC, ( aDrawInfo.m_DrawMode != GR_XOR ) ? GR_COPY : GR_XOR );
600  }
601 
602  COLOR4D hole_color = aDrawInfo.m_HoleColor;
603 
604  if( aDrawInfo. m_ShowNotPlatedHole ) // Draw a specific hole color
605  hole_color = aDrawInfo.m_NPHoleColor;
606 
607  switch( GetDrillShape() )
608  {
610  if( aDC->LogicalToDeviceXRel( hole ) > 1 ) // hole is drawn if hole > 1pixel
611  GRFilledCircle( aClipBox, aDC, holepos.x, holepos.y, hole, 0,
612  hole_color, hole_color );
613  break;
614 
616  {
617  wxPoint drl_start, drl_end;
618  GetOblongDrillGeometry( drl_start, drl_end, seg_width );
619  GRFilledSegment( aClipBox, aDC, holepos + drl_start,
620  holepos + drl_end, seg_width, hole_color );
621  }
622  break;
623 
624  default:
625  break;
626  }
627 
628  if( aDrawInfo.m_IsPrinting )
629  GRForceBlackPen( blackpenstate );
630  }
631 
632  GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
633 
634  // Draw "No connect" ( / or \ or cross X ) if necessary
635  if( GetNetCode() == 0 && aDrawInfo.m_ShowNCMark )
636  {
637  int dx0 = std::min( halfsize.x, halfsize.y );
638 
639  if( m_layerMask[F_Cu] ) /* Draw \ */
640  GRLine( aClipBox, aDC, holepos.x - dx0, holepos.y - dx0,
641  holepos.x + dx0, holepos.y + dx0, 0, aDrawInfo.m_NoNetMarkColor );
642 
643  if( m_layerMask[B_Cu] ) // Draw /
644  GRLine( aClipBox, aDC, holepos.x + dx0, holepos.y - dx0,
645  holepos.x - dx0, holepos.y + dx0, 0, aDrawInfo.m_NoNetMarkColor );
646  }
647 
648  if( !aDrawInfo.m_IsPrinting )
649  GRSetDrawMode( aDC, ( aDrawInfo.m_DrawMode != GR_XOR ) ? GR_COPY : GR_XOR );
650 
651  // Draw the pad number
652  if( !aDrawInfo.m_Display_padnum && !aDrawInfo.m_Display_netname )
653  return;
654 
655  wxPoint tpos0 = shape_pos; // Position of the centre of text
656  wxPoint tpos = tpos0;
657  wxSize AreaSize; // size of text area, normalized to AreaSize.y < AreaSize.x
658  int shortname_len = 0;
659 
660  if( aDrawInfo.m_Display_netname )
661  shortname_len = GetShortNetname().Len();
662 
663  if( GetShape() == PAD_SHAPE_CIRCLE )
664  angle = 0;
665 
666  AreaSize = m_Size;
667 
668  if( m_Size.y > m_Size.x )
669  {
670  angle += 900;
671  AreaSize.x = m_Size.y;
672  AreaSize.y = m_Size.x;
673  }
674 
675  if( shortname_len > 0 ) // if there is a netname, provides room to display this netname
676  {
677  AreaSize.y /= 2; // Text used only the upper area of the
678  // pad. The lower area displays the net name
679  tpos.y -= AreaSize.y / 2;
680  }
681 
682  // Calculate the position of text, that is the middle point of the upper
683  // area of the pad
684  RotatePoint( &tpos, shape_pos, angle );
685 
686  // Draw text with an angle between -90 deg and + 90 deg
687  double t_angle = angle;
688  NORMALIZE_ANGLE_90( t_angle );
689 
690  /* Note: in next calculations, texte size is calculated for 3 or more
691  * chars. Of course, pads numbers and nets names can have less than 3
692  * chars. but after some tries, i found this is gives the best look
693  */
694  constexpr int MIN_CHAR_COUNT = 3;
695 
696  unsigned int tsize;
697  EDA_RECT* clipBox = aDrawInfo.m_DrawPanel?
698  aDrawInfo.m_DrawPanel->GetClipBox() : NULL;
699 
700  if( aDrawInfo.m_Display_padnum )
701  {
702  int numpad_len = std::max( (int) m_name.Length(), MIN_CHAR_COUNT );
703  tsize = std::min( (int) AreaSize.y, AreaSize.x / numpad_len );
704 
705  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE ) // Not drawable when size too small.
706  {
707  // tsize reserve room for marges and segments thickness
708  tsize = ( tsize * 7 ) / 10;
709  DrawGraphicHaloText( clipBox, aDC, tpos,
710  aDrawInfo.m_Color, BLACK, WHITE,
711  m_name, t_angle,
712  wxSize( tsize , tsize ), GR_TEXT_HJUSTIFY_CENTER,
713  GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false );
714 
715  }
716  }
717 
718  // display the short netname, if exists
719  if( shortname_len == 0 )
720  return;
721 
722  shortname_len = std::max( shortname_len, MIN_CHAR_COUNT );
723  tsize = std::min( AreaSize.y, AreaSize.x / shortname_len );
724 
725  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE ) // Not drawable in size too small.
726  {
727  tpos = tpos0;
728 
729  if( aDrawInfo.m_Display_padnum )
730  tpos.y += AreaSize.y / 2;
731 
732  RotatePoint( &tpos, shape_pos, angle );
733 
734  // tsize reserve room for marges and segments thickness
735  tsize = ( tsize * 7 ) / 10;
736  DrawGraphicHaloText( clipBox, aDC, tpos,
737  aDrawInfo.m_Color, BLACK, WHITE,
738  GetShortNetname(), t_angle,
739  wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER,
740  GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false );
741  }
742 }
743 
744 
753  double aRotation, const wxSize& aMargin) const
754 {
755  int width;
756 
757  if( m_Size.y < m_Size.x ) // Build an horizontal equiv segment
758  {
759  int delta = ( m_Size.x - m_Size.y ) / 2;
760  aSegStart.x = -delta - aMargin.x;
761  aSegStart.y = 0;
762  aSegEnd.x = delta + aMargin.x;
763  aSegEnd.y = 0;
764  width = m_Size.y + ( aMargin.y * 2 );
765  }
766  else // Vertical oval: build a vertical equiv segment
767  {
768  int delta = ( m_Size.y -m_Size.x ) / 2;
769  aSegStart.x = 0;
770  aSegStart.y = -delta - aMargin.y;
771  aSegEnd.x = 0;
772  aSegEnd.y = delta + aMargin.y;
773  width = m_Size.x + ( aMargin.x * 2 );
774  }
775 
776  if( aRotation )
777  {
778  RotatePoint( &aSegStart, aRotation);
779  RotatePoint( &aSegEnd, aRotation);
780  }
781 
782  return width;
783 }
784 
785 
786 void D_PAD::BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue,
787  double aRotation ) const
788 {
789  wxSize delta;
790  wxSize halfsize;
791 
792  halfsize.x = m_Size.x >> 1;
793  halfsize.y = m_Size.y >> 1;
794 
795  switch( GetShape() )
796  {
797  case PAD_SHAPE_RECT:
798  // For rectangular shapes, inflate is easy
799  halfsize += aInflateValue;
800 
801  // Verify if do not deflate more than than size
802  // Only possible for inflate negative values.
803  if( halfsize.x < 0 )
804  halfsize.x = 0;
805 
806  if( halfsize.y < 0 )
807  halfsize.y = 0;
808  break;
809 
810  case PAD_SHAPE_TRAPEZOID:
811  // Trapezoidal pad: verify delta values
812  delta.x = ( m_DeltaSize.x >> 1 );
813  delta.y = ( m_DeltaSize.y >> 1 );
814 
815  // be sure delta values are not to large
816  if( (delta.x < 0) && (delta.x <= -halfsize.y) )
817  delta.x = -halfsize.y + 1;
818 
819  if( (delta.x > 0) && (delta.x >= halfsize.y) )
820  delta.x = halfsize.y - 1;
821 
822  if( (delta.y < 0) && (delta.y <= -halfsize.x) )
823  delta.y = -halfsize.x + 1;
824 
825  if( (delta.y > 0) && (delta.y >= halfsize.x) )
826  delta.y = halfsize.x - 1;
827  break;
828 
829  default: // is used only for rect and trap. pads
830  return;
831  }
832 
833  // Build the basic rectangular or trapezoid shape
834  // delta is null for rectangular shapes
835  aCoord[0].x = -halfsize.x - delta.y; // lower left
836  aCoord[0].y = +halfsize.y + delta.x;
837 
838  aCoord[1].x = -halfsize.x + delta.y; // upper left
839  aCoord[1].y = -halfsize.y - delta.x;
840 
841  aCoord[2].x = +halfsize.x - delta.y; // upper right
842  aCoord[2].y = -halfsize.y + delta.x;
843 
844  aCoord[3].x = +halfsize.x + delta.y; // lower right
845  aCoord[3].y = +halfsize.y - delta.x;
846 
847  // Offsetting the trapezoid shape id needed
848  // It is assumed delta.x or/and delta.y == 0
849  if( GetShape() == PAD_SHAPE_TRAPEZOID && (aInflateValue.x != 0 || aInflateValue.y != 0) )
850  {
851  double angle;
852  wxSize corr;
853 
854  if( delta.y ) // lower and upper segment is horizontal
855  {
856  // Calculate angle of left (or right) segment with vertical axis
857  angle = atan2( (double) m_DeltaSize.y, (double) m_Size.y );
858 
859  // left and right sides are moved by aInflateValue.x in their perpendicular direction
860  // We must calculate the corresponding displacement on the horizontal axis
861  // that is delta.x +- corr.x depending on the corner
862  corr.x = KiROUND( tan( angle ) * aInflateValue.x );
863  delta.x = KiROUND( aInflateValue.x / cos( angle ) );
864 
865  // Horizontal sides are moved up and down by aInflateValue.y
866  delta.y = aInflateValue.y;
867 
868  // corr.y = 0 by the constructor
869  }
870  else if( delta.x ) // left and right segment is vertical
871  {
872  // Calculate angle of lower (or upper) segment with horizontal axis
873  angle = atan2( (double) m_DeltaSize.x, (double) m_Size.x );
874 
875  // lower and upper sides are moved by aInflateValue.x in their perpendicular direction
876  // We must calculate the corresponding displacement on the vertical axis
877  // that is delta.y +- corr.y depending on the corner
878  corr.y = KiROUND( tan( angle ) * aInflateValue.y );
879  delta.y = KiROUND( aInflateValue.y / cos( angle ) );
880 
881  // Vertical sides are moved left and right by aInflateValue.x
882  delta.x = aInflateValue.x;
883 
884  // corr.x = 0 by the constructor
885  }
886  else // the trapezoid is a rectangle
887  {
888  delta = aInflateValue; // this pad is rectangular (delta null).
889  }
890 
891  aCoord[0].x += -delta.x - corr.x; // lower left
892  aCoord[0].y += delta.y + corr.y;
893 
894  aCoord[1].x += -delta.x + corr.x; // upper left
895  aCoord[1].y += -delta.y - corr.y;
896 
897  aCoord[2].x += delta.x - corr.x; // upper right
898  aCoord[2].y += -delta.y + corr.y;
899 
900  aCoord[3].x += delta.x + corr.x; // lower right
901  aCoord[3].y += delta.y - corr.y;
902 
903  /* test coordinates and clamp them if the offset correction is too large:
904  * Note: if a coordinate is bad, the other "symmetric" coordinate is bad
905  * So when a bad coordinate is found, the 2 symmetric coordinates
906  * are set to the minimun value (0)
907  */
908 
909  if( aCoord[0].x > 0 ) // lower left x coordinate must be <= 0
910  aCoord[0].x = aCoord[3].x = 0;
911 
912  if( aCoord[1].x > 0 ) // upper left x coordinate must be <= 0
913  aCoord[1].x = aCoord[2].x = 0;
914 
915  if( aCoord[0].y < 0 ) // lower left y coordinate must be >= 0
916  aCoord[0].y = aCoord[1].y = 0;
917 
918  if( aCoord[3].y < 0 ) // lower right y coordinate must be >= 0
919  aCoord[3].y = aCoord[2].y = 0;
920  }
921 
922  if( aRotation )
923  {
924  for( int ii = 0; ii < 4; ii++ )
925  RotatePoint( &aCoord[ii], aRotation );
926  }
927 }
Definition: colors.h:57
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:646
void DrawGraphicHaloText(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aPos, const COLOR4D aBgColor, COLOR4D aColor1, COLOR4D aColor2, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, void(*aCallback)(int x0, int y0, int xf, int yf), PLOTTER *aPlotter)
Draw graphic text with a border, so that it can be read on different backgrounds. ...
Definition: drawtxt.cpp:176
static int m_PadSketchModePenSize
Pen size used to draw pads in sketch mode (mode used to print pads on silkscreen layer) ...
Definition: class_pad.h:137
show a marker on pads with no nets
PAD_SHAPE_T GetAnchorPadShape() const
Function GetAnchorPadShape.
Definition: class_pad.h:226
bool m_Display_padnum
Definition: class_pad.h:75
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:398
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:296
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:106
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:65
void Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset=ZeroOffset) override
Function Draw BOARD_ITEMs have their own color information.
void BuildPadPolygon(wxPoint aCoord[4], wxSize aInflateValue, double aRotation) const
Function BuildPadPolygon Has meaning only for polygonal pads (trapezoid and rectangular) Build the Co...
int PointCount() const
Function PointCount()
Class BOARD to handle a board.
void TransformRoundRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, int aCircleToSegmentsCount)
Function TransformRoundRectToPolygon convert a rectangle with rounded corners to a polygon Convert ar...
int GetRoundRectCornerRadius() const
Function GetRoundRectCornerRadius Has meaning only for rounded rect pads.
Definition: class_pad.h:511
wxSize m_Size
X and Y size ( relative to orient 0)
Definition: class_pad.h:790
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:61
#define SEGCOUNT
void GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, COLOR4D Color)
Definition: gr_basic.cpp:488
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:381
COLOR4D m_NoNetMarkColor
Definition: class_pad.h:72
bool m_ShowNCMark
Definition: class_pad.h:79
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
int OutlineCount() const
Returns the number of outlines in the set
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:851
PCB_LAYER_ID m_Active_Layer
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:216
smd pads, back layer
static LSET FrontMask()
Function FrontMask returns a mask holding all technical layers and the external CU layer on front sid...
Definition: lset.cpp:745
void NORMALIZE_ANGLE_90(T &Angle)
Definition: trigo.h:299
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, wxPoint Points[], bool Fill, COLOR4D Color, COLOR4D BgColor)
Function GRClosedPoly draws a closed polygon onto the drawing context aDC and optionally fills and/or...
Definition: gr_basic.cpp:784
static const int delta[8][2]
Definition: solve.cpp:112
bool m_IsPrinting
Definition: class_pad.h:82
PCB_LAYER_ID ExtractLayer() const
Find the first set PCB_LAYER_ID.
Definition: lset.cpp:585
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings...
PCB_LAYER_ID
A quick note on layer IDs:
wxString m_name
Definition: class_pad.h:756
double a
Alpha component.
Definition: color4d.h:289
Class LSET is a set of PCB_LAYER_IDs.
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor) const
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon Used in filli...
Classes used in Pcbnew, CvPcb and GerbView.
void CustomShapeAsPolygonToBoardPosition(SHAPE_POLY_SET *aMergedPolygon, wxPoint aPosition, double aRotation) const
When created, the corners coordinates are relative to the pad position, orientation 0...
void Inflate(int aFactor, int aCircleSegmentsCount)
Performs outline inflation/deflation, using round corners.
#define MIN_TEXT_SIZE
Definition: drawtxt.h:43
void GRForceBlackPen(bool flagforce)
Function GRForceBlackPen.
Definition: gr_basic.cpp:277
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:41
Class SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:591
PCB_GENERAL_SETTINGS & Settings()
int GetSolderMaskMargin() const
Function GetSolderMaskMargin.
Definition: class_pad.cpp:577
GR_DRAWMODE m_DrawMode
Definition: class_pad.h:67
const wxPoint & GetPosition() const override
Definition: class_pad.h:220
EDA_DRAW_PANEL * m_DrawPanel
Definition: class_pad.h:66
COLOR4D m_HoleColor
Definition: class_pad.h:70
const wxSize & GetSize() const
Definition: class_pad.h:269
PCB_LAYER_ID m_Route_Layer_BOTTOM
EDA_RECT * GetClipBox()
bool m_ShowNotPlatedHole
Definition: class_pad.h:80
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:174
SHAPE_POLY_SET m_customShapeAsPolygon
for free shape pads: the set of basic shapes, merged as one polygon, in local coordinates, orient 0, coordinates relative to m_Pos
Definition: class_pad.h:773
void DrawShape(EDA_RECT *aClipBox, wxDC *aDC, PAD_DRAWINFO &aDrawInfo)
Function DrawShape basic function to draw a pad.
wxSize m_DeltaSize
delta on rectangular shapes
Definition: class_pad.h:820
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:358
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:62
int m_PadClearance
Definition: class_pad.h:73
COLORS_DESIGN_SETTINGS & Colors()
int GetNetCode() const
Function GetNetCode.
LSET m_layerMask
Bitwise layer :1= copper layer, 15= cmp, 2..14 = internal layers 16 .
Definition: class_pad.h:816
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
int BuildSegmentFromOvalShape(wxPoint &aSegStart, wxPoint &aSegEnd, double aRotation, const wxSize &aMargin) const
Function BuildSegmentFromOvalShape Has meaning only for OVAL (and ROUND) pads Build an equivalent seg...
wxPoint m_Offset
Definition: class_pad.h:83
smd pads, front layer
Board layer functions and definitions.
handle color for not plated holes
void GetOblongDrillGeometry(wxPoint &aStartPoint, wxPoint &aEndPoint, int &aWidth) const
Function GetOblongDrillGeometry calculates the start point, end point and width of an equivalent segm...
Definition: class_pad.cpp:749
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
Class SHAPE_LINE_CHAIN.
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, wxPoint aStart, wxPoint aEnd, int aWidth, COLOR4D aColor)
Definition: gr_basic.cpp:599
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
LSET GetVisibleLayers() const
Function GetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:828
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:189
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:375
Class EDA_RECT handles the component boundary box.
wxSize GetSolderPasteMargin() const
Function GetSolderPasteMargin.
Definition: class_pad.cpp:610
void GetRoundRectCornerCenters(wxPoint aCenters[4], int aRadius, const wxPoint &aPosition, const wxSize &aSize, double aRotation)
Helper function GetRoundRectCornerCenters Has meaning only for rounded rect Returns the centers of th...
The common library.
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_pad.cpp:546
static LSET BackMask()
Function BackMask returns a mask holding all technical layers and the external CU layer on back side...
Definition: lset.cpp:752
Definition: colors.h:49
wxPoint ShapePos() const
Definition: class_pad.cpp:500
bool m_ShowPadFilled
Definition: class_pad.h:77
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
COLOR4D m_NPHoleColor
Definition: class_pad.h:71
This file is part of the common libary.
COLOR4D m_Color
Definition: class_pad.h:68
VECTOR2I & Point(int aIndex)
Function Point()
wxSize m_Drill
Drill diam (drill shape = PAD_CIRCLE) or drill size (shape = OVAL) for drill shape = PAD_CIRCLE...
Definition: class_pad.h:786
Definition: colors.h:45
double m_Orient
in 1/10 degrees
Definition: class_pad.h:827
bool m_Display_netname
Definition: class_pad.h:76
bool GetGRForceBlackPenState(void)
Function GetGRForceBlackPenState.
Definition: gr_basic.cpp:287
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: class_pad.h:637
wxSize m_Mask_margin
Definition: class_pad.h:74
Definition: colors.h:68
PCB_LAYER_ID m_Route_Layer_TOP
#define DO_NOT_DRAW
Used to disable draw function.
Definition: base_struct.h:139
#define min(a, b)
Definition: auxiliary.h:85
wxPoint m_Pos
pad Position on board
Definition: class_pad.h:758
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline) ...
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
const wxString & GetShortNetname() const
Function GetShortNetname.