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) 2016 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-2016 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 <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;
65  m_PadClearance = 0;
66  m_Display_padnum = true;
67  m_Display_netname = true;
68  m_ShowPadFilled = true;
69  m_ShowNCMark = true;
70  m_ShowNotPlatedHole = false;
71  m_IsPrinting = false;
72 }
73 
74 
75 void D_PAD::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDraw_mode,
76  const wxPoint& aOffset )
77 {
78  wxSize mask_margin; // margin (clearance) used for some non copper layers
79 
80 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
81  int showActualMaskSize = 0; /* Layer number if the actual pad size on mask layer can
82  * be displayed i.e. if only one layer is shown for this pad
83  * and this layer is a mask (solder mask or solder paste
84  */
85 #endif
86 
87  if( m_Flags & DO_NOT_DRAW )
88  return;
89 
90  PAD_DRAWINFO drawInfo;
91 
92  drawInfo.m_Offset = aOffset;
93 
94  /* We can show/hide pads from the layer manager.
95  * options are show/hide pads on front and/or back side of the board
96  * For through pads, we hide them only if both sides are hidden.
97  * smd pads on back are hidden for all layers (copper and technical layers)
98  * on back side of the board
99  * smd pads on front are hidden for all layers (copper and technical layers)
100  * on front side of the board
101  * ECO, edge and Draw layers and not considered
102  */
103 
104  BOARD* brd = GetBoard();
105  bool frontVisible = brd->IsElementVisible( LAYER_PAD_FR );
106  bool backVisible = brd->IsElementVisible( LAYER_PAD_BK );
107 
108  if( !frontVisible && !backVisible )
109  return;
110 
111  // If pad is only on front side (no layer on back side)
112  // and if hide front side pads is enabled, do not draw
113  if( !frontVisible && !( m_layerMask & LSET::BackMask() ).any() )
114  return;
115 
116  // If pad is only on back side (no layer on front side)
117  // and if hide back side pads is enabled, do not draw
118  if( !backVisible && !( m_layerMask & LSET::FrontMask() ).any() )
119  return;
120 
121  PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();
122 
123  wxCHECK_RET( frame != NULL, wxT( "Panel has no parent frame window." ) );
124 
125  DISPLAY_OPTIONS* displ_opts = (DISPLAY_OPTIONS*)frame->GetDisplayOptions();
126  PCB_SCREEN* screen = frame->GetScreen();
127 
128  if( displ_opts && displ_opts->m_DisplayPadFill == SKETCH )
129  drawInfo.m_ShowPadFilled = false;
130  else
131  drawInfo.m_ShowPadFilled = true;
132 
134 
135  if( m_layerMask[F_Cu] )
136  {
137  color = brd->GetVisibleElementColor( LAYER_PAD_FR );
138  }
139 
140  if( m_layerMask[B_Cu] )
141  {
142  color = color.LegacyMix( brd->GetVisibleElementColor( LAYER_PAD_BK ) );
143  }
144 
145  if( color == BLACK ) // Not on a visible copper layer (i.e. still nothing to show)
146  {
147  // If the pad is on only one tech layer, use the layer color else use DARKGRAY
148  LSET mask_non_copper_layers = m_layerMask & ~LSET::AllCuMask();
149 
150 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
151  mask_non_copper_layers &= brd->GetVisibleLayers();
152 #endif
153  PCB_LAYER_ID pad_layer = mask_non_copper_layers.ExtractLayer();
154 
155  switch( (int) pad_layer )
156  {
157  case UNDEFINED_LAYER: // More than one layer
158  color = DARKGRAY;
159  break;
160 
161  case UNSELECTED_LAYER: // Shouldn't really happen...
162  break;
163 
164  default:
165  color = brd->GetLayerColor( pad_layer );
166 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
167  showActualMaskSize = pad_layer;
168 #endif
169  }
170  }
171 
172  // if SMD or connector pad and high contrast mode
173  if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
175  displ_opts && displ_opts->m_ContrastModeDisplay )
176  {
177  // when routing tracks
178  if( frame->GetToolId() == ID_TRACK_BUTT )
179  {
180  PCB_LAYER_ID routeTop = screen->m_Route_Layer_TOP;
181  PCB_LAYER_ID routeBot = screen->m_Route_Layer_BOTTOM;
182 
183  // if routing between copper and component layers,
184  // or the current layer is one of said 2 external copper layers,
185  // then highlight only the current layer.
186  if( ( screen->m_Active_Layer == F_Cu || screen->m_Active_Layer == B_Cu ) ||
187  ( routeTop==F_Cu && routeBot==B_Cu ) ||
188  ( routeTop==B_Cu && routeBot==F_Cu )
189  )
190  {
191  if( !IsOnLayer( screen->m_Active_Layer ) )
192  color = COLOR4D( DARKDARKGRAY );
193  }
194  // else routing between an internal signal layer and some other
195  // layer. Grey out all PAD_ATTRIB_SMD pads not on current or the single
196  // selected external layer.
197  else if( !IsOnLayer( screen->m_Active_Layer )
198  && !IsOnLayer( routeTop )
199  && !IsOnLayer( routeBot ) )
200  {
201  color = COLOR4D( DARKDARKGRAY );
202  }
203  }
204  // when not edting tracks, show PAD_ATTRIB_SMD components not on active layer
205  // as greyed out
206  else
207  {
208  if( !IsOnLayer( screen->m_Active_Layer ) )
209  color = COLOR4D( DARKDARKGRAY );
210  }
211  }
212 
213 #ifdef SHOW_PADMASK_REAL_SIZE_AND_COLOR
214  if( showActualMaskSize )
215  {
216  switch( showActualMaskSize )
217  {
218  case B_Mask:
219  case F_Mask:
220  mask_margin.x = mask_margin.y = GetSolderMaskMargin();
221  break;
222 
223  case B_Paste:
224  case F_Paste:
225  mask_margin = GetSolderPasteMargin();
226  break;
227 
228  default:
229  // Another layer which has no margin to handle
230  break;
231  }
232  }
233 #endif
234 
235  // if Contrast mode is ON and a technical layer active, show pads on this
236  // layer so we can see pads on paste or solder layer and the size of the
237  // mask
238  if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
239  displ_opts && displ_opts->m_ContrastModeDisplay && !IsCopperLayer( screen->m_Active_Layer ) )
240  {
241  if( IsOnLayer( screen->m_Active_Layer ) )
242  {
243  color = brd->GetLayerColor( screen->m_Active_Layer );
244 
245  // In high contrast mode, and if the active layer is the mask
246  // layer shows the pad size with the mask clearance
247  switch( screen->m_Active_Layer )
248  {
249  case B_Mask:
250  case F_Mask:
251  mask_margin.x = mask_margin.y = GetSolderMaskMargin();
252  break;
253 
254  case B_Paste:
255  case F_Paste:
256  mask_margin = GetSolderPasteMargin();
257  break;
258 
259  default:
260  break;
261  }
262  }
263  else
264  color = DARKDARKGRAY;
265  }
266 
267  if( ( aDraw_mode & GR_HIGHLIGHT ) && !( aDraw_mode & GR_AND ) )
268  color.SetToLegacyHighlightColor();
269 
270  bool DisplayIsol = displ_opts && displ_opts->m_DisplayPadIsol;
271 
272  if( !( m_layerMask & LSET::AllCuMask() ).any() )
273  DisplayIsol = false;
274 
277  {
278  drawInfo.m_ShowNotPlatedHole = true;
280  }
281 
282  drawInfo.m_DrawMode = aDraw_mode;
283  drawInfo.m_Color = color;
284  drawInfo.m_DrawPanel = aPanel;
285  drawInfo.m_Mask_margin = mask_margin;
287  drawInfo.m_IsPrinting = screen->m_IsPrinting;
288  color.a = 0.666;
289 
290  /* Get the pad clearance. This has a meaning only for Pcbnew.
291  * for CvPcb GetClearance() creates debug errors because
292  * there is no net classes so a call to GetClearance() is made only when
293  * needed (never needed in CvPcb)
294  */
295  drawInfo.m_PadClearance = DisplayIsol ? GetClearance() : 0;
296 
297  // Draw the pad number
298  if( displ_opts && !displ_opts->m_DisplayPadNum )
299  drawInfo.m_Display_padnum = false;
300 
301  if( displ_opts &&
302  (( displ_opts ->m_DisplayNetNamesMode == 0 ) || ( displ_opts->m_DisplayNetNamesMode == 2 )) )
303  drawInfo.m_Display_netname = false;
304 
305  // Display net names is restricted to pads that are on the active layer
306  // in high contrast mode display
307  if( ( aDraw_mode & GR_ALLOW_HIGHCONTRAST ) &&
308  !IsOnLayer( screen->m_Active_Layer ) && displ_opts && displ_opts->m_ContrastModeDisplay )
309  drawInfo.m_Display_netname = false;
310 
311  DrawShape( aPanel->GetClipBox(), aDC, drawInfo );
312 }
313 
314 
315 void D_PAD::DrawShape( EDA_RECT* aClipBox, wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
316 {
317  wxPoint coord[12];
318  double angle = m_Orient;
319  int seg_width;
320 
321  GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
322 
323  // calculate pad shape position :
324  wxPoint shape_pos = ShapePos() - aDrawInfo.m_Offset;
325 
326  wxSize halfsize = m_Size;
327  halfsize.x >>= 1;
328  halfsize.y >>= 1;
329 
330  switch( GetShape() )
331  {
332  case PAD_SHAPE_CIRCLE:
333  if( aDrawInfo.m_ShowPadFilled )
334  GRFilledCircle( aClipBox, aDC, shape_pos.x, shape_pos.y,
335  halfsize.x + aDrawInfo.m_Mask_margin.x, 0,
336  aDrawInfo.m_Color, aDrawInfo.m_Color );
337  else
338  GRCircle( aClipBox, aDC, shape_pos.x, shape_pos.y,
339  halfsize.x + aDrawInfo.m_Mask_margin.x,
340  m_PadSketchModePenSize, aDrawInfo.m_Color );
341 
342  if( aDrawInfo.m_PadClearance )
343  {
344  GRCircle( aClipBox,
345  aDC, shape_pos.x, shape_pos.y,
346  halfsize.x + aDrawInfo.m_PadClearance,
347  0, aDrawInfo.m_Color );
348  }
349 
350  break;
351 
352  case PAD_SHAPE_OVAL:
353  {
354  wxPoint segStart, segEnd;
355  seg_width = BuildSegmentFromOvalShape(segStart, segEnd, angle,
356  aDrawInfo.m_Mask_margin);
357  segStart += shape_pos;
358  segEnd += shape_pos;
359 
360  if( aDrawInfo.m_ShowPadFilled )
361  {
362  GRFillCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
363  seg_width, aDrawInfo.m_Color );
364  }
365  else
366  {
367  GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
368  seg_width, m_PadSketchModePenSize, aDrawInfo.m_Color );
369  }
370 
371  // Draw the clearance line
372  if( aDrawInfo.m_PadClearance )
373  {
374  seg_width += 2 * aDrawInfo.m_PadClearance;
375  GRCSegm( aClipBox, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y,
376  seg_width, aDrawInfo.m_Color );
377  }
378  }
379  break;
380 
381  case PAD_SHAPE_RECT:
382  case PAD_SHAPE_TRAPEZOID:
383  BuildPadPolygon( coord, aDrawInfo.m_Mask_margin, angle );
384 
385  for( int ii = 0; ii < 4; ii++ )
386  coord[ii] += shape_pos;
387 
388  GRClosedPoly( aClipBox, aDC, 4, coord, aDrawInfo.m_ShowPadFilled,
389  aDrawInfo.m_ShowPadFilled ? 0 : m_PadSketchModePenSize,
390  aDrawInfo.m_Color, aDrawInfo.m_Color );
391 
392  if( aDrawInfo.m_PadClearance )
393  {
394  #define SEGCOUNT 32 // number of segments to approximate a circle
395  SHAPE_POLY_SET outline;
397 
398  // Draw the polygon: Inflate creates only one convex polygon
399  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
400 
401  GRClosedPoly( aClipBox, aDC, poly.PointCount(),
402  (wxPoint*)&poly.Point( 0 ), false, 0,
403  aDrawInfo.m_Color, aDrawInfo.m_Color );
404  }
405  break;
406 
407  case PAD_SHAPE_ROUNDRECT:
408  {
409  // Use solder[Paste/Mask]size or pad size to build pad shape to draw
410  wxSize size( GetSize() );
411  size += aDrawInfo.m_Mask_margin * 2;
412  int corner_radius = GetRoundRectCornerRadius( size );
413 
414  // Draw the polygon: Inflate creates only one convex polygon
415  SHAPE_POLY_SET outline;
416  bool filled = aDrawInfo.m_ShowPadFilled;
417 
418  if( filled )
419  {
420  wxPoint centers[4];
421  GetRoundRectCornerCenters( centers, corner_radius, shape_pos,
422  size, GetOrientation() );
423  GRClosedPoly( aClipBox, aDC, 4, centers, true, corner_radius*2,
424  aDrawInfo.m_Color, aDrawInfo.m_Color );
425  }
426  else
427  {
428  TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
429  corner_radius, 64 );
430 
431  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
432 
433  GRClosedPoly( aClipBox, aDC, poly.PointCount(),
434  (wxPoint*)&poly.Point( 0 ), aDrawInfo.m_ShowPadFilled, 0,
435  aDrawInfo.m_Color, aDrawInfo.m_Color );
436  }
437 
438  if( aDrawInfo.m_PadClearance )
439  {
440  outline.RemoveAllContours();
441  size = GetSize();
442  size.x += aDrawInfo.m_PadClearance * 2;
443  size.y += aDrawInfo.m_PadClearance * 2;
444  corner_radius = GetRoundRectCornerRadius() + aDrawInfo.m_PadClearance;
445 
446  TransformRoundRectToPolygon( outline, shape_pos, size, GetOrientation(),
447  corner_radius, 32 );
448 
449  // Draw the polygon: Inflate creates only one convex polygon
450  SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
451 
452  GRClosedPoly( aClipBox, aDC, clearance_poly.PointCount(),
453  (wxPoint*)&clearance_poly.Point( 0 ), false, 0,
454  aDrawInfo.m_Color, aDrawInfo.m_Color );
455  }
456  }
457  break;
458 
459  default:
460  break;
461  }
462 
463  // Draw the pad hole
464  wxPoint holepos = m_Pos - aDrawInfo.m_Offset;
465  int hole = m_Drill.x >> 1;
466 
467  bool drawhole = hole > 0;
468 
469  if( !aDrawInfo.m_ShowPadFilled && !aDrawInfo.m_ShowNotPlatedHole )
470  drawhole = false;
471 
472  if( drawhole )
473  {
474  bool blackpenstate = false;
475 
476  if( aDrawInfo.m_IsPrinting )
477  {
478  blackpenstate = GetGRForceBlackPenState();
479  GRForceBlackPen( false );
480  aDrawInfo.m_HoleColor = WHITE;
481  aDrawInfo.m_NPHoleColor = WHITE;
482  }
483  else
484  {
485  GRSetDrawMode( aDC, ( aDrawInfo.m_DrawMode != GR_XOR ) ? GR_COPY : GR_XOR );
486  }
487 
488  COLOR4D hole_color = aDrawInfo.m_HoleColor;
489 
490  if( aDrawInfo. m_ShowNotPlatedHole ) // Draw a specific hole color
491  hole_color = aDrawInfo.m_NPHoleColor;
492 
493  switch( GetDrillShape() )
494  {
496  if( aDC->LogicalToDeviceXRel( hole ) > 1 ) // hole is drawn if hole > 1pixel
497  GRFilledCircle( aClipBox, aDC, holepos.x, holepos.y, hole, 0,
498  hole_color, hole_color );
499  break;
500 
502  {
503  wxPoint drl_start, drl_end;
504  GetOblongDrillGeometry( drl_start, drl_end, seg_width );
505  GRFilledSegment( aClipBox, aDC, holepos + drl_start,
506  holepos + drl_end, seg_width, hole_color );
507  }
508  break;
509 
510  default:
511  break;
512  }
513 
514  if( aDrawInfo.m_IsPrinting )
515  GRForceBlackPen( blackpenstate );
516  }
517 
518  GRSetDrawMode( aDC, aDrawInfo.m_DrawMode );
519 
520  // Draw "No connect" ( / or \ or cross X ) if necessary
521  if( GetNetCode() == 0 && aDrawInfo.m_ShowNCMark )
522  {
523  int dx0 = std::min( halfsize.x, halfsize.y );
524  COLOR4D nc_color = COLOR4D( BLUE );
525 
526  if( m_layerMask[F_Cu] ) /* Draw \ */
527  GRLine( aClipBox, aDC, holepos.x - dx0, holepos.y - dx0,
528  holepos.x + dx0, holepos.y + dx0, 0, nc_color );
529 
530  if( m_layerMask[B_Cu] ) // Draw /
531  GRLine( aClipBox, aDC, holepos.x + dx0, holepos.y - dx0,
532  holepos.x - dx0, holepos.y + dx0, 0, nc_color );
533  }
534 
535  if( !aDrawInfo.m_IsPrinting )
536  GRSetDrawMode( aDC, ( aDrawInfo.m_DrawMode != GR_XOR ) ? GR_COPY : GR_XOR );
537 
538  // Draw the pad number
539  if( !aDrawInfo.m_Display_padnum && !aDrawInfo.m_Display_netname )
540  return;
541 
542  wxPoint tpos0 = shape_pos; // Position of the centre of text
543  wxPoint tpos = tpos0;
544  wxSize AreaSize; // size of text area, normalized to AreaSize.y < AreaSize.x
545  int shortname_len = 0;
546 
547  if( aDrawInfo.m_Display_netname )
548  shortname_len = GetShortNetname().Len();
549 
550  if( GetShape() == PAD_SHAPE_CIRCLE )
551  angle = 0;
552 
553  AreaSize = m_Size;
554 
555  if( m_Size.y > m_Size.x )
556  {
557  angle += 900;
558  AreaSize.x = m_Size.y;
559  AreaSize.y = m_Size.x;
560  }
561 
562  if( shortname_len > 0 ) // if there is a netname, provides room to display this netname
563  {
564  AreaSize.y /= 2; // Text used only the upper area of the
565  // pad. The lower area displays the net name
566  tpos.y -= AreaSize.y / 2;
567  }
568 
569  // Calculate the position of text, that is the middle point of the upper
570  // area of the pad
571  RotatePoint( &tpos, shape_pos, angle );
572 
573  // Draw text with an angle between -90 deg and + 90 deg
574  double t_angle = angle;
575  NORMALIZE_ANGLE_90( t_angle );
576 
577  /* Note: in next calculations, texte size is calculated for 3 or more
578  * chars. Of course, pads numbers and nets names can have less than 3
579  * chars. but after some tries, i found this is gives the best look
580  */
581  #define MIN_CHAR_COUNT 3
582  wxString buffer;
583 
584  int tsize;
585  EDA_RECT* clipBox = aDrawInfo.m_DrawPanel?
586  aDrawInfo.m_DrawPanel->GetClipBox() : NULL;
587 
588  if( aDrawInfo.m_Display_padnum )
589  {
590  StringPadName( buffer );
591  int numpad_len = buffer.Len();
592  numpad_len = std::max( numpad_len, MIN_CHAR_COUNT );
593 
594  tsize = std::min( AreaSize.y, AreaSize.x / numpad_len );
595 
596  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE ) // Not drawable when size too small.
597  {
598  // tsize reserve room for marges and segments thickness
599  tsize = ( tsize * 7 ) / 10;
600  DrawGraphicHaloText( clipBox, aDC, tpos,
601  aDrawInfo.m_Color, BLACK, WHITE,
602  buffer, t_angle,
603  wxSize( tsize , tsize ), GR_TEXT_HJUSTIFY_CENTER,
604  GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false );
605 
606  }
607  }
608 
609  // display the short netname, if exists
610  if( shortname_len == 0 )
611  return;
612 
613  shortname_len = std::max( shortname_len, MIN_CHAR_COUNT );
614  tsize = std::min( AreaSize.y, AreaSize.x / shortname_len );
615 
616  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE ) // Not drawable in size too small.
617  {
618  tpos = tpos0;
619 
620  if( aDrawInfo.m_Display_padnum )
621  tpos.y += AreaSize.y / 2;
622 
623  RotatePoint( &tpos, shape_pos, angle );
624 
625  // tsize reserve room for marges and segments thickness
626  tsize = ( tsize * 7 ) / 10;
627  DrawGraphicHaloText( clipBox, aDC, tpos,
628  aDrawInfo.m_Color, BLACK, WHITE,
629  GetShortNetname(), t_angle,
630  wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER,
631  GR_TEXT_VJUSTIFY_CENTER, tsize / 7, false, false );
632  }
633 }
634 
635 
644  double aRotation, const wxSize& aMargin) const
645 {
646  int width;
647 
648  if( m_Size.y < m_Size.x ) // Build an horizontal equiv segment
649  {
650  int delta = ( m_Size.x - m_Size.y ) / 2;
651  aSegStart.x = -delta - aMargin.x;
652  aSegStart.y = 0;
653  aSegEnd.x = delta + aMargin.x;
654  aSegEnd.y = 0;
655  width = m_Size.y + ( aMargin.y * 2 );
656  }
657  else // Vertical oval: build a vertical equiv segment
658  {
659  int delta = ( m_Size.y -m_Size.x ) / 2;
660  aSegStart.x = 0;
661  aSegStart.y = -delta - aMargin.y;
662  aSegEnd.x = 0;
663  aSegEnd.y = delta + aMargin.y;
664  width = m_Size.x + ( aMargin.x * 2 );
665  }
666 
667  if( aRotation )
668  {
669  RotatePoint( &aSegStart, aRotation);
670  RotatePoint( &aSegEnd, aRotation);
671  }
672 
673  return width;
674 }
675 
676 
677 void D_PAD::BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue,
678  double aRotation ) const
679 {
680  wxSize delta;
681  wxSize halfsize;
682 
683  halfsize.x = m_Size.x >> 1;
684  halfsize.y = m_Size.y >> 1;
685 
686  switch( GetShape() )
687  {
688  case PAD_SHAPE_RECT:
689  // For rectangular shapes, inflate is easy
690  halfsize += aInflateValue;
691 
692  // Verify if do not deflate more than than size
693  // Only possible for inflate negative values.
694  if( halfsize.x < 0 )
695  halfsize.x = 0;
696 
697  if( halfsize.y < 0 )
698  halfsize.y = 0;
699  break;
700 
701  case PAD_SHAPE_TRAPEZOID:
702  // Trapezoidal pad: verify delta values
703  delta.x = ( m_DeltaSize.x >> 1 );
704  delta.y = ( m_DeltaSize.y >> 1 );
705 
706  // be sure delta values are not to large
707  if( (delta.x < 0) && (delta.x <= -halfsize.y) )
708  delta.x = -halfsize.y + 1;
709 
710  if( (delta.x > 0) && (delta.x >= halfsize.y) )
711  delta.x = halfsize.y - 1;
712 
713  if( (delta.y < 0) && (delta.y <= -halfsize.x) )
714  delta.y = -halfsize.x + 1;
715 
716  if( (delta.y > 0) && (delta.y >= halfsize.x) )
717  delta.y = halfsize.x - 1;
718  break;
719 
720  default: // is used only for rect and trap. pads
721  return;
722  }
723 
724  // Build the basic rectangular or trapezoid shape
725  // delta is null for rectangular shapes
726  aCoord[0].x = -halfsize.x - delta.y; // lower left
727  aCoord[0].y = +halfsize.y + delta.x;
728 
729  aCoord[1].x = -halfsize.x + delta.y; // upper left
730  aCoord[1].y = -halfsize.y - delta.x;
731 
732  aCoord[2].x = +halfsize.x - delta.y; // upper right
733  aCoord[2].y = -halfsize.y + delta.x;
734 
735  aCoord[3].x = +halfsize.x + delta.y; // lower right
736  aCoord[3].y = +halfsize.y - delta.x;
737 
738  // Offsetting the trapezoid shape id needed
739  // It is assumed delta.x or/and delta.y == 0
740  if( GetShape() == PAD_SHAPE_TRAPEZOID && (aInflateValue.x != 0 || aInflateValue.y != 0) )
741  {
742  double angle;
743  wxSize corr;
744 
745  if( delta.y ) // lower and upper segment is horizontal
746  {
747  // Calculate angle of left (or right) segment with vertical axis
748  angle = atan2( (double) m_DeltaSize.y, (double) m_Size.y );
749 
750  // left and right sides are moved by aInflateValue.x in their perpendicular direction
751  // We must calculate the corresponding displacement on the horizontal axis
752  // that is delta.x +- corr.x depending on the corner
753  corr.x = KiROUND( tan( angle ) * aInflateValue.x );
754  delta.x = KiROUND( aInflateValue.x / cos( angle ) );
755 
756  // Horizontal sides are moved up and down by aInflateValue.y
757  delta.y = aInflateValue.y;
758 
759  // corr.y = 0 by the constructor
760  }
761  else if( delta.x ) // left and right segment is vertical
762  {
763  // Calculate angle of lower (or upper) segment with horizontal axis
764  angle = atan2( (double) m_DeltaSize.x, (double) m_Size.x );
765 
766  // lower and upper sides are moved by aInflateValue.x in their perpendicular direction
767  // We must calculate the corresponding displacement on the vertical axis
768  // that is delta.y +- corr.y depending on the corner
769  corr.y = KiROUND( tan( angle ) * aInflateValue.y );
770  delta.y = KiROUND( aInflateValue.y / cos( angle ) );
771 
772  // Vertical sides are moved left and right by aInflateValue.x
773  delta.x = aInflateValue.x;
774 
775  // corr.x = 0 by the constructor
776  }
777  else // the trapezoid is a rectangle
778  {
779  delta = aInflateValue; // this pad is rectangular (delta null).
780  }
781 
782  aCoord[0].x += -delta.x - corr.x; // lower left
783  aCoord[0].y += delta.y + corr.y;
784 
785  aCoord[1].x += -delta.x + corr.x; // upper left
786  aCoord[1].y += -delta.y - corr.y;
787 
788  aCoord[2].x += delta.x - corr.x; // upper right
789  aCoord[2].y += -delta.y + corr.y;
790 
791  aCoord[3].x += delta.x + corr.x; // lower right
792  aCoord[3].y += delta.y - corr.y;
793 
794  /* test coordinates and clamp them if the offset correction is too large:
795  * Note: if a coordinate is bad, the other "symmetric" coordinate is bad
796  * So when a bad coordinate is found, the 2 symmetric coordinates
797  * are set to the minimun value (0)
798  */
799 
800  if( aCoord[0].x > 0 ) // lower left x coordinate must be <= 0
801  aCoord[0].x = aCoord[3].x = 0;
802 
803  if( aCoord[1].x > 0 ) // upper left x coordinate must be <= 0
804  aCoord[1].x = aCoord[2].x = 0;
805 
806  if( aCoord[0].y < 0 ) // lower left y coordinate must be >= 0
807  aCoord[0].y = aCoord[1].y = 0;
808 
809  if( aCoord[3].y < 0 ) // lower right y coordinate must be >= 0
810  aCoord[3].y = aCoord[2].y = 0;
811  }
812 
813  if( aRotation )
814  {
815  for( int ii = 0; ii < 4; ii++ )
816  RotatePoint( &aCoord[ii], aRotation );
817  }
818 }
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:639
COLOR4D GetLayerColor(PCB_LAYER_ID aLayer) const
Function GetLayerColor gets a layer color for any valid layer, including non-copper ones...
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:83
#define MIN_CHAR_COUNT
show a marker on pads with no nets
bool IsElementVisible(GAL_LAYER_ID LAYER_aPCB) const
Function IsElementVisible tests whether a given element category is visible.
bool m_Display_padnum
Definition: class_pad.h:66
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:238
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:290
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:63
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()
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color)
Definition: gr_basic.cpp:352
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:351
wxSize m_Size
X and Y size ( relative to orient 0)
Definition: class_pad.h:620
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
#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:481
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:221
COLOR4D GetVisibleElementColor(GAL_LAYER_ID LAYER_aPCB)
Function GetVisibleElementColor returns the color of a pcb visible element.
bool m_ShowNCMark
Definition: class_pad.h:70
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:833
PCB_LAYER_ID m_Active_Layer
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:166
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:738
void NORMALIZE_ANGLE_90(T &Angle)
Definition: trigo.h:277
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:777
static const int delta[8][2]
Definition: solve.cpp:112
bool m_IsPrinting
Definition: class_pad.h:73
void * GetDisplayOptions() override
Function GetDisplayOptions returns the display options current in use Display options are relative to...
PCB_LAYER_ID ExtractLayer() const
Find the first set PCB_LAYER_ID.
Definition: lset.cpp:578
PCB_LAYER_ID
A quick note on layer IDs:
double a
Alpha component.
Definition: color4d.h:284
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.
#define MIN_TEXT_SIZE
Definition: drawtxt.h:43
void GRForceBlackPen(bool flagforce)
Function GRForceBlackPen.
Definition: gr_basic.cpp:271
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:584
int GetSolderMaskMargin() const
Function GetSolderMaskMargin.
Definition: class_pad.cpp:537
GR_DRAWMODE m_DrawMode
Definition: class_pad.h:59
EDA_DRAW_PANEL * m_DrawPanel
Definition: class_pad.h:58
bool m_ContrastModeDisplay
Definition: pcbstruct.h:85
COLOR4D m_HoleColor
Definition: class_pad.h:62
const wxSize & GetSize() const
Definition: class_pad.h:182
PCB_LAYER_ID m_Route_Layer_BOTTOM
EDA_RECT * GetClipBox()
bool m_ShowNotPlatedHole
Definition: class_pad.h:71
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:175
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:647
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:60
int m_PadClearance
Definition: class_pad.h:64
Class DISPLAY_OPTIONS handles display options like enable/disable some optional drawings.
Definition: pcbstruct.h:62
int GetNetCode() const
Function GetNetCode.
LSET m_layerMask
Bitwise layer :1= copper layer, 15= cmp, 2..14 = internal layers 16 .
Definition: class_pad.h:643
bool m_DisplayPadFill
Definition: pcbstruct.h:65
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...
bool m_DisplayPadIsol
Definition: pcbstruct.h:68
wxPoint m_Offset
Definition: class_pad.h:74
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:718
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:166
Class SHAPE_LINE_CHAIN.
bool m_DisplayPadNum
Definition: pcbstruct.h:67
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, wxPoint aStart, wxPoint aEnd, int aWidth, COLOR4D aColor)
Definition: gr_basic.cpp:592
int GetToolId() const
Definition: draw_frame.h:406
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:791
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:175
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:214
Class EDA_RECT handles the component boundary box.
wxSize GetSolderPasteMargin() const
Function GetSolderPasteMargin.
Definition: class_pad.cpp:570
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 m_DisplayNetNamesMode
Definition: pcbstruct.h:78
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_pad.cpp:506
PCB_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
static LSET BackMask()
Function BackMask returns a mask holding all technical layers and the external CU layer on back side...
Definition: lset.cpp:745
Definition: colors.h:49
wxPoint ShapePos() const
Definition: class_pad.cpp:418
bool m_ShowPadFilled
Definition: class_pad.h:68
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:63
This file is part of the common libary.
COLOR4D m_Color
Definition: class_pad.h:60
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:616
Definition: colors.h:45
double m_Orient
in 1/10 degrees
Definition: class_pad.h:654
void StringPadName(wxString &text) const
Definition: class_pad.cpp:442
bool m_Display_netname
Definition: class_pad.h:67
bool GetGRForceBlackPenState(void)
Function GetGRForceBlackPenState.
Definition: gr_basic.cpp:281
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:479
wxSize m_Mask_margin
Definition: class_pad.h:65
Definition: colors.h:68
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
PCB_LAYER_ID m_Route_Layer_TOP
#define DO_NOT_DRAW
Used to disable draw function.
Definition: base_struct.h:125
#define min(a, b)
Definition: auxiliary.h:85
wxPoint m_Pos
pad Position on board
Definition: class_pad.h:607
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
const wxString & GetShortNetname() const
Function GetShortNetname.