KiCad PCB EDA Suite
pad_print_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-2019 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 
27 #include <class_board.h>
28 #include <common.h>
30 #include <gr_text.h>
31 #include <fctsys.h>
33 #include <gr_basic.h>
35 #include <pcb_edit_frame.h>
36 #include <pcb_screen.h>
37 #include <pcbnew.h>
38 #include <pcbnew_id.h> // ID_TRACK_BUTT
39 #include <trigo.h>
40 
41 
42 // Helper class to store parameters used to draw a pad
44 {
45  m_Color = BLACK;
46  m_HoleColor = BLACK; // could be DARKGRAY;
49  m_PadClearance = 0;
50  m_Display_padnum = true;
51  m_Display_netname = true;
52  m_ShowPadFilled = true;
53  m_ShowNCMark = true;
54  m_ShowNotPlatedHole = false;
55  m_IsPrinting = false;
56 }
57 
58 
59 void D_PAD::Print( PCB_BASE_FRAME* aFrame, wxDC* aDC, const wxPoint& aOffset )
60 {
61  wxSize mask_margin; // margin (clearance) used for some non copper layers
62 
63  if( m_Flags & DO_NOT_DRAW )
64  return;
65 
66  PAD_DRAWINFO drawInfo;
67 
68  drawInfo.m_Offset = aOffset;
69 
70  /* We can show/hide pads from the layer manager.
71  * options are show/hide pads on front and/or back side of the board
72  * For through pads, we hide them only if both sides are hidden.
73  * smd pads on back are hidden for all layers (copper and technical layers)
74  * on back side of the board
75  * smd pads on front are hidden for all layers (copper and technical layers)
76  * on front side of the board
77  * ECO, edge and Draw layers and not considered
78  */
79 
80  BOARD* brd = GetBoard();
81 
82  const auto& cds = aFrame->Settings().Colors();
83 
84  bool frontVisible = brd->IsElementVisible( LAYER_PAD_FR );
85  bool backVisible = brd->IsElementVisible( LAYER_PAD_BK );
86 
87  if( !frontVisible && !backVisible )
88  return;
89 
90  // If pad is only on front side (no layer on back side)
91  // and if hide front side pads is enabled, do not draw
92  if( !frontVisible && !( m_layerMask & LSET::BackMask() ).any() )
93  return;
94 
95  // If pad is only on back side (no layer on front side)
96  // and if hide back side pads is enabled, do not draw
97  if( !backVisible && !( m_layerMask & LSET::FrontMask() ).any() )
98  return;
99 
100 
101  auto displ_opts = (PCB_DISPLAY_OPTIONS*)( aFrame->GetDisplayOptions() );
102  PCB_SCREEN* screen = aFrame->GetScreen();
103 
104  if( displ_opts && displ_opts->m_DisplayPadFill == SKETCH )
105  drawInfo.m_ShowPadFilled = false;
106  else
107  drawInfo.m_ShowPadFilled = true;
108 
110 
111  if( m_layerMask[F_Cu] )
112  {
113  color = cds.GetItemColor( LAYER_PAD_FR );
114  }
115 
116  if( m_layerMask[B_Cu] )
117  {
118  color = color.LegacyMix( cds.GetItemColor( LAYER_PAD_BK ) );
119  }
120 
121  if( color == BLACK ) // Not on a visible copper layer (i.e. still nothing to show)
122  {
123  // If the pad is on only one tech layer, use the layer color else use DARKGRAY
124  LSET mask_non_copper_layers = m_layerMask & ~LSET::AllCuMask();
125 
126  PCB_LAYER_ID pad_layer = mask_non_copper_layers.ExtractLayer();
127 
128  switch( (int) pad_layer )
129  {
130  case UNDEFINED_LAYER: // More than one layer
131  color = DARKGRAY;
132  break;
133 
134  case UNSELECTED_LAYER: // Shouldn't really happen...
135  break;
136 
137  default:
138  color = cds.GetLayerColor( pad_layer );
139  }
140  }
141 
142  if( ( IsOnLayer( B_Paste ) && brd->IsLayerVisible( B_Paste ) ) ||
143  ( IsOnLayer( F_Paste ) && brd->IsLayerVisible( F_Paste ) ) )
144  {
145  mask_margin = GetSolderPasteMargin();
146  }
147 
148  if( ( IsOnLayer( B_Mask ) && brd->IsLayerVisible( B_Mask ) ) ||
149  ( IsOnLayer( F_Mask ) && brd->IsLayerVisible( F_Mask ) ) )
150  {
151  mask_margin.x = std::max( mask_margin.x, GetSolderMaskMargin() );
152  mask_margin.y = std::max( mask_margin.y, GetSolderMaskMargin() );
153  }
154 
155  bool DisplayIsol = displ_opts && displ_opts->m_DisplayPadIsol;
156 
157  if( !( m_layerMask & LSET::AllCuMask() ).any() )
158  DisplayIsol = false;
159 
162  {
163  drawInfo.m_ShowNotPlatedHole = true;
164  drawInfo.m_NPHoleColor = cds.GetItemColor( LAYER_NON_PLATEDHOLES );
165  }
166  // Don't let pads that *should* be NPTHs get lost
167  else if ( PadShouldBeNPTH() )
168  {
169  drawInfo.m_ShowNotPlatedHole = true;
170  drawInfo.m_NPHoleColor = cds.GetItemColor( LAYER_MOD_TEXT_INVISIBLE );
171  }
172 
173  drawInfo.m_Color = color;
174  drawInfo.m_NoNetMarkColor = cds.GetItemColor( LAYER_NO_CONNECTS );
175  drawInfo.m_Mask_margin = mask_margin;
177  drawInfo.m_IsPrinting = screen->m_IsPrinting;
178  color.a = 0.666;
179 
180  /* Get the pad clearance. This has a meaning only for Pcbnew.
181  * for CvPcb GetClearance() creates debug errors because
182  * there is no net classes so a call to GetClearance() is made only when
183  * needed (never needed in CvPcb)
184  */
185  drawInfo.m_PadClearance = DisplayIsol ? GetClearance() : 0;
186 
187  // Draw the pad number
188  if( displ_opts && !displ_opts->m_DisplayPadNum )
189  drawInfo.m_Display_padnum = false;
190 
191  if( displ_opts &&
192  (( displ_opts ->m_DisplayNetNamesMode == 0 ) || ( displ_opts->m_DisplayNetNamesMode == 2 )) )
193  drawInfo.m_Display_netname = false;
194 
195  PrintShape( aDC, drawInfo );
196 }
197 
198 
199 void D_PAD::PrintShape( wxDC* aDC, PAD_DRAWINFO& aDrawInfo )
200 {
201  #define SEGCOUNT 32 // number of segments to approximate a circle
202  wxPoint coord[12];
203  double angle = m_Orient;
204  int seg_width;
205 
206  // calculate pad shape position :
207  wxPoint shape_pos = ShapePos() - aDrawInfo.m_Offset;
208 
209  wxSize halfsize = m_Size;
210  halfsize.x >>= 1;
211  halfsize.y >>= 1;
212 
213  switch( GetShape() )
214  {
215  case PAD_SHAPE_CIRCLE:
216  if( aDrawInfo.m_ShowPadFilled )
217  GRFilledCircle( nullptr, aDC, shape_pos.x, shape_pos.y,
218  halfsize.x + aDrawInfo.m_Mask_margin.x, 0,
219  aDrawInfo.m_Color, aDrawInfo.m_Color );
220  else
221  GRCircle( nullptr, aDC, shape_pos.x, shape_pos.y,
222  halfsize.x + aDrawInfo.m_Mask_margin.x,
223  m_PadSketchModePenSize, aDrawInfo.m_Color );
224 
225  if( aDrawInfo.m_PadClearance )
226  {
227  GRCircle( nullptr, aDC, shape_pos.x, shape_pos.y,
228  halfsize.x + aDrawInfo.m_PadClearance, 0, aDrawInfo.m_Color );
229  }
230 
231  break;
232 
233  case PAD_SHAPE_OVAL:
234  {
235  wxPoint segStart, segEnd;
236  seg_width = BuildSegmentFromOvalShape( segStart, segEnd, angle, aDrawInfo.m_Mask_margin );
237  segStart += shape_pos;
238  segEnd += shape_pos;
239 
240  if( aDrawInfo.m_ShowPadFilled )
241  {
242  GRFillCSegm( nullptr, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y, seg_width,
243  aDrawInfo.m_Color );
244  }
245  else
246  {
247  GRCSegm( nullptr, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y, seg_width,
248  m_PadSketchModePenSize, aDrawInfo.m_Color );
249  }
250 
251  // Draw the clearance line
252  if( aDrawInfo.m_PadClearance )
253  {
254  seg_width += 2 * aDrawInfo.m_PadClearance;
255  GRCSegm( nullptr, aDC, segStart.x, segStart.y, segEnd.x, segEnd.y, seg_width,
256  aDrawInfo.m_Color );
257  }
258  }
259  break;
260 
261  case PAD_SHAPE_RECT:
262  case PAD_SHAPE_TRAPEZOID:
263  BuildPadPolygon( coord, aDrawInfo.m_Mask_margin, angle );
264 
265  for( int ii = 0; ii < 4; ii++ )
266  coord[ii] += shape_pos;
267 
268  GRClosedPoly( nullptr, aDC, 4, coord, aDrawInfo.m_ShowPadFilled,
269  aDrawInfo.m_ShowPadFilled ? 0 : m_PadSketchModePenSize,
270  aDrawInfo.m_Color, aDrawInfo.m_Color );
271 
272  if( aDrawInfo.m_PadClearance )
273  {
274  SHAPE_POLY_SET outline;
276 
277  // Draw the polygon: Inflate creates only one convex polygon
278  if( outline.OutlineCount() > 0 )
279  {
280  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
281 
282  if( poly.PointCount() > 0 )
283  {
284  GRClosedPoly( nullptr, aDC, poly.PointCount(), (wxPoint*)&poly.Point( 0 ),
285  false, 0, aDrawInfo.m_Color, aDrawInfo.m_Color );
286  }
287  }
288  }
289  break;
290 
292  case PAD_SHAPE_ROUNDRECT:
293  {
294  // Use solder[Paste/Mask]size or pad size to build pad shape to draw
295  wxSize size( GetSize() );
296  size += aDrawInfo.m_Mask_margin * 2;
297  int corner_radius = GetRoundRectCornerRadius( size );
298  bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
299 
300  SHAPE_POLY_SET outline;
301  TransformRoundChamferedRectToPolygon( outline, shape_pos, size, GetOrientation(),
302  corner_radius, GetChamferRectRatio(),
303  doChamfer ? GetChamferPositions() : 0,
304  ARC_HIGH_DEF );
305 
306  // Draw the polygon: Inflate creates only one convex polygon
307  bool filled = aDrawInfo.m_ShowPadFilled;
308 
309  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
310 
311  GRClosedPoly( nullptr, aDC, poly.PointCount(), (wxPoint*)&poly.Point( 0 ), filled, 0,
312  aDrawInfo.m_Color, aDrawInfo.m_Color );
313 
314  if( aDrawInfo.m_PadClearance )
315  {
316  outline.RemoveAllContours();
317  size = GetSize();
318  size.x += aDrawInfo.m_PadClearance * 2;
319  size.y += aDrawInfo.m_PadClearance * 2;
320  corner_radius = GetRoundRectCornerRadius() + aDrawInfo.m_PadClearance;
321 
322  TransformRoundChamferedRectToPolygon( outline, shape_pos, size, GetOrientation(),
323  corner_radius, GetChamferRectRatio(),
324  doChamfer ? GetChamferPositions() : 0,
325  ARC_HIGH_DEF );
326 
327  // Draw the polygon: Inflate creates only one convex polygon
328  SHAPE_LINE_CHAIN& clearance_poly = outline.Outline( 0 );
329 
330  GRClosedPoly( nullptr, aDC, clearance_poly.PointCount(),
331  (wxPoint*)&clearance_poly.Point( 0 ), false, 0,
332  aDrawInfo.m_Color, aDrawInfo.m_Color );
333  }
334  }
335  break;
336 
337  case PAD_SHAPE_CUSTOM:
338  {
339  // The full shape has 2 items
340  // 1- The anchor pad: a round or rect pad located at pad position
341  // 2- The custom complex shape
342  // Note: The anchor pad shape is containing by the custom complex shape polygon
343  // The anchor pad is shown to help user to see where is the anchor, only in sketch mode
344  // (In filled mode, it is merged with the basic shapes)
345  wxPoint pad_pos = GetPosition() - aDrawInfo.m_Offset;
346 
347  // In sketch mode only: Draw the anchor pad: a round or rect pad
348  if( !aDrawInfo.m_ShowPadFilled )
349  {
351  {
352  wxPoint poly[4];
353  poly[0] = wxPoint( - halfsize.x, - halfsize.y );
354  poly[1] = wxPoint( - halfsize.x, + halfsize.y );
355  poly[2] = wxPoint( + halfsize.x, + halfsize.y );
356  poly[3] = wxPoint( + halfsize.x, - halfsize.y );
357 
358  for( int ii = 0; ii < 4; ++ii )
359  {
360  RotatePoint( &poly[ii], m_Orient );
361  poly[ii] += pad_pos;
362  }
363 
364  GRClosedPoly( nullptr, aDC, 4, poly, false, 0, aDrawInfo.m_Color,
365  aDrawInfo.m_Color );
366  }
367  else
368  {
369  GRCircle( nullptr, aDC, pad_pos.x, pad_pos.y, halfsize.x,
370  m_PadSketchModePenSize, aDrawInfo.m_Color );
371  }
372  }
373 
374  SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
375  outline.Append( m_customShapeAsPolygon );
376  CustomShapeAsPolygonToBoardPosition( &outline, pad_pos, GetOrientation() );
377  SHAPE_LINE_CHAIN* poly;
378 
379  if( aDrawInfo.m_Mask_margin.x )
380  {
381  int numSegs = GetArcToSegmentCount( aDrawInfo.m_Mask_margin.x, ARC_HIGH_DEF, 360.0 );
382  outline.InflateWithLinkedHoles(
383  aDrawInfo.m_Mask_margin.x, numSegs, SHAPE_POLY_SET::PM_FAST );
384  }
385 
386  // Draw the polygon: only one polygon is expected
387  // However we provide a multi polygon shape drawing
388  // ( can happen with CUSTOM pads and negative margins )
389  for( int jj = 0; jj < outline.OutlineCount(); ++jj )
390  {
391  poly = &outline.Outline( jj );
392 
393  GRClosedPoly( nullptr, aDC, poly->PointCount(), (wxPoint*)&poly->Point( 0 ),
394  aDrawInfo.m_ShowPadFilled, 0, aDrawInfo.m_Color, aDrawInfo.m_Color );
395  }
396 
397  if( aDrawInfo.m_PadClearance )
398  {
399  SHAPE_POLY_SET clearance_outline;
400  clearance_outline.Append( outline );
401 
402  int numSegs = GetArcToSegmentCount( aDrawInfo.m_PadClearance, ARC_HIGH_DEF, 360.0 );
403  clearance_outline.InflateWithLinkedHoles(
404  aDrawInfo.m_PadClearance, numSegs, SHAPE_POLY_SET::PM_FAST );
405 
406  for( int jj = 0; jj < clearance_outline.OutlineCount(); ++jj )
407  {
408  poly = &clearance_outline.Outline( jj );
409 
410  if( poly->PointCount() > 0 )
411  {
412  GRClosedPoly( nullptr, aDC, poly->PointCount(), (wxPoint*)&poly->Point( 0 ),
413  false, 0, aDrawInfo.m_Color, aDrawInfo.m_Color );
414  }
415  }
416  }
417 
418  break;
419  }
420  }
421 
422  // Draw the pad hole
423  wxPoint holepos = m_Pos - aDrawInfo.m_Offset;
424  int hole = m_Drill.x >> 1;
425 
426  bool drawhole = hole > 0;
427 
428  if( !aDrawInfo.m_ShowPadFilled && !aDrawInfo.m_ShowNotPlatedHole )
429  drawhole = false;
430 
431  if( drawhole )
432  {
433  bool blackpenstate = false;
434  COLOR4D fillcolor = aDrawInfo.m_ShowNotPlatedHole? aDrawInfo.m_NPHoleColor :
435  aDrawInfo.m_HoleColor;
436  COLOR4D hole_color = fillcolor;
437 
438  fillcolor = COLOR4D::WHITE;
439  blackpenstate = GetGRForceBlackPenState();
440  GRForceBlackPen( false );
441 
442  if( blackpenstate )
443  hole_color = COLOR4D::BLACK;
444 
445  switch( GetDrillShape() )
446  {
448  if( aDC->LogicalToDeviceXRel( hole ) > 1 ) // hole is drawn if hole > 1pixel
449  GRFilledCircle( nullptr, aDC, holepos.x, holepos.y, hole, 0, hole_color, fillcolor );
450  break;
451 
453  {
454  wxPoint drl_start, drl_end;
455  GetOblongDrillGeometry( drl_start, drl_end, seg_width );
456  drl_start += holepos;
457  drl_end += holepos;
458  GRFilledSegment( nullptr, aDC, drl_start, drl_end, seg_width, fillcolor );
459  GRCSegm( nullptr, aDC, drl_start, drl_end, seg_width, hole_color );
460  }
461  break;
462 
463  default:
464  break;
465  }
466 
467  if( aDrawInfo.m_IsPrinting )
468  GRForceBlackPen( blackpenstate );
469  }
470 
471  // Draw "No connect" ( / or \ or cross X ) if necessary
472  if( GetNetCode() == 0 && aDrawInfo.m_ShowNCMark )
473  {
474  int dx0 = std::min( halfsize.x, halfsize.y );
475 
476  if( m_layerMask[F_Cu] ) /* Draw \ */
477  GRLine( nullptr, aDC, holepos.x - dx0, holepos.y - dx0,
478  holepos.x + dx0, holepos.y + dx0, 0, aDrawInfo.m_NoNetMarkColor );
479 
480  if( m_layerMask[B_Cu] ) // Draw /
481  GRLine( nullptr, aDC, holepos.x + dx0, holepos.y - dx0,
482  holepos.x - dx0, holepos.y + dx0, 0, aDrawInfo.m_NoNetMarkColor );
483  }
484 
485  // Draw the pad number
486  if( !aDrawInfo.m_Display_padnum && !aDrawInfo.m_Display_netname )
487  return;
488 
489  wxPoint tpos0 = shape_pos; // Position of the centre of text
490  wxPoint tpos = tpos0;
491  wxSize AreaSize; // size of text area, normalized to AreaSize.y < AreaSize.x
492  wxString shortname;
493  int shortname_len = 0;
494 
495  if( aDrawInfo.m_Display_netname )
496  {
497  shortname = UnescapeString( GetShortNetname() );
498  shortname_len = shortname.Len();
499  }
500 
501  if( GetShape() == PAD_SHAPE_CIRCLE )
502  angle = 0;
503 
504  AreaSize = m_Size;
505 
506  if( m_Size.y > m_Size.x )
507  {
508  angle += 900;
509  AreaSize.x = m_Size.y;
510  AreaSize.y = m_Size.x;
511  }
512 
513  if( shortname_len > 0 ) // if there is a netname, provides room to display this netname
514  {
515  AreaSize.y /= 2; // Text used only the upper area of the
516  // pad. The lower area displays the net name
517  tpos.y -= AreaSize.y / 2;
518  }
519 
520  // Calculate the position of text, that is the middle point of the upper
521  // area of the pad
522  RotatePoint( &tpos, shape_pos, angle );
523 
524  // Draw text with an angle between -90 deg and + 90 deg
525  double t_angle = angle;
526  NORMALIZE_ANGLE_90( t_angle );
527 
528  /* Note: in next calculations, texte size is calculated for 3 or more
529  * chars. Of course, pads numbers and nets names can have less than 3
530  * chars. but after some tries, i found this is gives the best look
531  */
532  constexpr int MIN_CHAR_COUNT = 3;
533 
534  unsigned int tsize;
535 
536  if( aDrawInfo.m_Display_padnum )
537  {
538  int numpad_len = std::max( (int) m_name.Length(), MIN_CHAR_COUNT );
539  tsize = std::min( (int) AreaSize.y, AreaSize.x / numpad_len );
540 
541  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE ) // Not drawable when size too small.
542  {
543  // tsize reserve room for marges and segments thickness
544  tsize = ( tsize * 7 ) / 10;
545  GRHaloText( aDC, tpos, aDrawInfo.m_Color, BLACK, WHITE, m_name, t_angle,
546  wxSize( tsize , tsize ), GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER,
547  tsize / 7, false, false );
548 
549  }
550  }
551 
552  // display the short netname, if exists
553  if( shortname_len == 0 )
554  return;
555 
556  shortname_len = std::max( shortname_len, MIN_CHAR_COUNT );
557  tsize = std::min( AreaSize.y, AreaSize.x / shortname_len );
558 
559  if( aDC->LogicalToDeviceXRel( tsize ) >= MIN_TEXT_SIZE ) // Not drawable in size too small.
560  {
561  tpos = tpos0;
562 
563  if( aDrawInfo.m_Display_padnum )
564  tpos.y += AreaSize.y / 2;
565 
566  RotatePoint( &tpos, shape_pos, angle );
567 
568  // tsize reserve room for marges and segments thickness
569  tsize = ( tsize * 7 ) / 10;
570  GRHaloText( aDC, tpos, aDrawInfo.m_Color, BLACK, WHITE, shortname, t_angle,
571  wxSize( tsize, tsize ), GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_VJUSTIFY_CENTER,
572  tsize / 7, false, false );
573  }
574 }
575 
576 
584 int D_PAD::BuildSegmentFromOvalShape( wxPoint& aSegStart, wxPoint& aSegEnd, double aRotation,
585  const wxSize& aMargin ) const
586 {
587  int width;
588 
589  if( m_Size.y < m_Size.x ) // Build an horizontal equiv segment
590  {
591  int delta = ( m_Size.x - m_Size.y ) / 2;
592  aSegStart.x = -delta - aMargin.x;
593  aSegStart.y = 0;
594  aSegEnd.x = delta + aMargin.x;
595  aSegEnd.y = 0;
596  width = m_Size.y + ( aMargin.y * 2 );
597  }
598  else // Vertical oval: build a vertical equiv segment
599  {
600  int delta = ( m_Size.y -m_Size.x ) / 2;
601  aSegStart.x = 0;
602  aSegStart.y = -delta - aMargin.y;
603  aSegEnd.x = 0;
604  aSegEnd.y = delta + aMargin.y;
605  width = m_Size.x + ( aMargin.x * 2 );
606  }
607 
608  if( aRotation )
609  {
610  RotatePoint( &aSegStart, aRotation);
611  RotatePoint( &aSegEnd, aRotation);
612  }
613 
614  return width;
615 }
616 
617 
618 void D_PAD::BuildPadPolygon( wxPoint aCoord[4], wxSize aInflateValue,
619  double aRotation ) const
620 {
621  wxSize delta;
622  wxSize halfsize;
623 
624  halfsize.x = m_Size.x >> 1;
625  halfsize.y = m_Size.y >> 1;
626 
627  switch( GetShape() )
628  {
629  case PAD_SHAPE_RECT:
630  // For rectangular shapes, inflate is easy
631  halfsize += aInflateValue;
632 
633  // Verify if do not deflate more than than size
634  // Only possible for inflate negative values.
635  if( halfsize.x < 0 )
636  halfsize.x = 0;
637 
638  if( halfsize.y < 0 )
639  halfsize.y = 0;
640  break;
641 
642  case PAD_SHAPE_TRAPEZOID:
643  // Trapezoidal pad: verify delta values
644  delta.x = ( m_DeltaSize.x >> 1 );
645  delta.y = ( m_DeltaSize.y >> 1 );
646 
647  // be sure delta values are not to large
648  if( (delta.x < 0) && (delta.x <= -halfsize.y) )
649  delta.x = -halfsize.y + 1;
650 
651  if( (delta.x > 0) && (delta.x >= halfsize.y) )
652  delta.x = halfsize.y - 1;
653 
654  if( (delta.y < 0) && (delta.y <= -halfsize.x) )
655  delta.y = -halfsize.x + 1;
656 
657  if( (delta.y > 0) && (delta.y >= halfsize.x) )
658  delta.y = halfsize.x - 1;
659  break;
660 
661  default: // is used only for rect and trap. pads
662  return;
663  }
664 
665  // Build the basic rectangular or trapezoid shape
666  // delta is null for rectangular shapes
667  aCoord[0].x = -halfsize.x - delta.y; // lower left
668  aCoord[0].y = +halfsize.y + delta.x;
669 
670  aCoord[1].x = -halfsize.x + delta.y; // upper left
671  aCoord[1].y = -halfsize.y - delta.x;
672 
673  aCoord[2].x = +halfsize.x - delta.y; // upper right
674  aCoord[2].y = -halfsize.y + delta.x;
675 
676  aCoord[3].x = +halfsize.x + delta.y; // lower right
677  aCoord[3].y = +halfsize.y - delta.x;
678 
679  // Offsetting the trapezoid shape id needed
680  // It is assumed delta.x or/and delta.y == 0
681  if( GetShape() == PAD_SHAPE_TRAPEZOID && (aInflateValue.x != 0 || aInflateValue.y != 0) )
682  {
683  double angle;
684  wxSize corr;
685 
686  if( delta.y ) // lower and upper segment is horizontal
687  {
688  // Calculate angle of left (or right) segment with vertical axis
689  angle = atan2( (double) m_DeltaSize.y, (double) m_Size.y );
690 
691  // left and right sides are moved by aInflateValue.x in their perpendicular direction
692  // We must calculate the corresponding displacement on the horizontal axis
693  // that is delta.x +- corr.x depending on the corner
694  corr.x = KiROUND( tan( angle ) * aInflateValue.x );
695  delta.x = KiROUND( aInflateValue.x / cos( angle ) );
696 
697  // Horizontal sides are moved up and down by aInflateValue.y
698  delta.y = aInflateValue.y;
699 
700  // corr.y = 0 by the constructor
701  }
702  else if( delta.x ) // left and right segment is vertical
703  {
704  // Calculate angle of lower (or upper) segment with horizontal axis
705  angle = atan2( (double) m_DeltaSize.x, (double) m_Size.x );
706 
707  // lower and upper sides are moved by aInflateValue.x in their perpendicular direction
708  // We must calculate the corresponding displacement on the vertical axis
709  // that is delta.y +- corr.y depending on the corner
710  corr.y = KiROUND( tan( angle ) * aInflateValue.y );
711  delta.y = KiROUND( aInflateValue.y / cos( angle ) );
712 
713  // Vertical sides are moved left and right by aInflateValue.x
714  delta.x = aInflateValue.x;
715 
716  // corr.x = 0 by the constructor
717  }
718  else // the trapezoid is a rectangle
719  {
720  delta = aInflateValue; // this pad is rectangular (delta null).
721  }
722 
723  aCoord[0].x += -delta.x - corr.x; // lower left
724  aCoord[0].y += delta.y + corr.y;
725 
726  aCoord[1].x += -delta.x + corr.x; // upper left
727  aCoord[1].y += -delta.y - corr.y;
728 
729  aCoord[2].x += delta.x - corr.x; // upper right
730  aCoord[2].y += -delta.y + corr.y;
731 
732  aCoord[3].x += delta.x + corr.x; // lower right
733  aCoord[3].y += delta.y - corr.y;
734 
735  /* test coordinates and clamp them if the offset correction is too large:
736  * Note: if a coordinate is bad, the other "symmetric" coordinate is bad
737  * So when a bad coordinate is found, the 2 symmetric coordinates
738  * are set to the minimun value (0)
739  */
740 
741  if( aCoord[0].x > 0 ) // lower left x coordinate must be <= 0
742  aCoord[0].x = aCoord[3].x = 0;
743 
744  if( aCoord[1].x > 0 ) // upper left x coordinate must be <= 0
745  aCoord[1].x = aCoord[2].x = 0;
746 
747  if( aCoord[0].y < 0 ) // lower left y coordinate must be >= 0
748  aCoord[0].y = aCoord[1].y = 0;
749 
750  if( aCoord[3].y < 0 ) // lower right y coordinate must be >= 0
751  aCoord[3].y = aCoord[2].y = 0;
752  }
753 
754  if( aRotation )
755  {
756  for( int ii = 0; ii < 4; ii++ )
757  RotatePoint( &aCoord[ii], aRotation );
758  }
759 }
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:143
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:73
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:115
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:66
PAD_SHAPE_T GetAnchorPadShape() const
Function GetAnchorPadShape.
Definition: class_pad.h:231
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...
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:825
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aApproxErrorMax, int aMinSegPerCircleCount)
convert a rectangle with rounded corners and/or chamfered corners to a polygon Convert rounded corner...
int color
Definition: DXF_plotter.cpp:62
wxSize m_Size
X and Y size ( relative to orient 0)
Definition: class_pad.h:858
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:312
COLOR4D m_NoNetMarkColor
Definition: class_pad.h:70
bool m_ShowNCMark
Definition: class_pad.h:77
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:623
int PointCount() const
Function PointCount()
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:331
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:556
bool m_IsPrinting
Definition: class_pad.h:80
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:429
void * GetDisplayOptions() override
Function GetDisplayOptions returns the display options current in use Display options are relative to...
int GetChamferPositions() const
has meaning only for chamfered rect pads
Definition: class_pad.h:693
int GetSolderMaskMargin() const
Function GetSolderMaskMargin.
Definition: class_pad.cpp:627
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:823
Class LSET is a set of PCB_LAYER_IDs.
void GRForceBlackPen(bool flagforce)
Function GRForceBlackPen.
Definition: gr_basic.cpp:201
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:415
PCB_GENERAL_SETTINGS & Settings()
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:412
double GetChamferRectRatio() const
has meaning only for chamfered rect pads
Definition: class_pad.h:670
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
void Print(PCB_BASE_FRAME *aFrame, wxDC *aDC, const wxPoint &aOffset=ZeroOffset) override
Function Print BOARD_ITEMs have their own color information.
COLOR4D m_HoleColor
Definition: class_pad.h:68
#define MIN_TEXT_SIZE
Definition: gr_text.h:43
a few functions useful in geometry calculations.
void PrintShape(wxDC *aDC, PAD_DRAWINFO &aDrawInfo)
Function PrintShape basic function to print a pad.
bool m_ShowNotPlatedHole
Definition: class_pad.h:78
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:841
wxSize m_DeltaSize
delta on rectangular shapes
Definition: class_pad.h:891
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:230
int m_PadClearance
Definition: class_pad.h:71
bool m_IsPrinting
Definition: base_screen.h:139
COLORS_DESIGN_SETTINGS & Colors()
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:887
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aMaxError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon Used in filli...
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:459
void GRHaloText(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.
Definition: gr_text.cpp:171
wxPoint m_Offset
Definition: class_pad.h:81
smd pads, front layer
Board layer functions and definitions.
wxSize GetSolderPasteMargin() const
Function GetSolderPasteMargin.
Definition: class_pad.cpp:673
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:161
Class SHAPE_LINE_CHAIN.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:406
void CustomShapeAsPolygonToBoardPosition(SHAPE_POLY_SET *aMergedPolygon, wxPoint aPosition, double aRotation) const
When created, the corners coordinates are relative to the pad position, orientation 0,...
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:123
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, wxPoint aStart, wxPoint aEnd, int aWidth, COLOR4D aColor)
Definition: gr_basic.cpp:423
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:600
STATUS_FLAGS m_Flags
Flag bits for editing and other uses.
Definition: base_struct.h:187
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
wxPoint ShapePos() const
Definition: class_pad.cpp:570
The common library.
void InflateWithLinkedHoles(int aFactor, int aCircleSegmentsCount, POLYGON_MODE aFastMode)
Performs outline inflation/deflation, using round corners.
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_pad.cpp:596
PCB_SCREEN * GetScreen() const override
Return 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:782
Definition: colors.h:49
bool m_ShowPadFilled
Definition: class_pad.h:75
int GetRoundRectCornerRadius() const
Function GetRoundRectCornerRadius Has meaning only for rounded rect pads.
Definition: class_pad.h:546
COLOR4D m_NPHoleColor
Definition: class_pad.h:69
COLOR4D m_Color
Definition: class_pad.h:66
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:854
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:221
Definition: colors.h:45
double m_Orient
in 1/10 degrees
Definition: class_pad.h:898
bool m_Display_netname
Definition: class_pad.h:74
const wxSize & GetSize() const
Definition: class_pad.h:284
bool GetGRForceBlackPenState(void)
Function GetGRForceBlackPenState.
Definition: gr_basic.cpp:211
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:715
const wxPoint GetPosition() const override
Definition: class_pad.h:225
wxSize m_Mask_margin
Definition: class_pad.h:72
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:1300
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
#define DO_NOT_DRAW
Used to disable draw function.
Definition: base_struct.h:132
const wxString & GetShortNetname() const
Function GetShortNetname.
#define min(a, b)
Definition: auxiliary.h:85
wxPoint m_Pos
pad Position on board
Definition: class_pad.h:826
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