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