KiCad PCB EDA Suite
common_plotGERBER_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, jp.charras at wanadoo.fr
5  * Copyright (C) 2016 KiCad Developers, see CHANGELOG.TXT for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <fctsys.h>
31 #include <gr_basic.h>
32 #include <trigo.h>
33 #include <wxstruct.h>
34 #include <base_struct.h>
35 #include <common.h>
36 #include <plot_common.h>
37 #include <macros.h>
38 #include <kicad_string.h>
40 
41 #include <build_version.h>
42 
43 #include <plot_auxiliary_data.h>
44 
45 
47 {
48  workFile = NULL;
49  finalFile = NULL;
50  currentAperture = apertures.end();
52 
53  // number of digits after the point (number of digits of the mantissa
54  // Be carefull: the Gerber coordinates are stored in an integer
55  // so 6 digits (inches) or 5 digits (mm) is a good value
56  // To avoid overflow, 7 digits (inches) or 6 digits is a max.
57  // with lower values than 6 digits (inches) or 5 digits (mm),
58  // Creating self-intersecting polygons from non-intersecting polygons
59  // happen easily.
60  m_gerberUnitInch = false;
61  m_gerberUnitFmt = 6;
62  m_useX2Attributes = false;
63  m_useNetAttributes = true;
64 }
65 
66 
67 void GERBER_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
68  double aScale, bool aMirror )
69 {
70  wxASSERT( aMirror == false );
71  m_plotMirror = false;
72  plotOffset = aOffset;
73  wxASSERT( aScale == 1 ); // aScale parameter is not used in Gerber
74  plotScale = 1; // Plot scale is *always* 1.0
75 
76  m_IUsPerDecimil = aIusPerDecimil;
77  // gives now a default value to iuPerDeviceUnit (because the units of the caller is now known)
78  // which could be modified later by calling SetGerberCoordinatesFormat()
79  iuPerDeviceUnit = pow( 10.0, m_gerberUnitFmt ) / ( m_IUsPerDecimil * 10000.0 );
80 
81  // We don't handle the filmbox, and it's more useful to keep the
82  // origin at the origin
83  paperSize.x = 0;
84  paperSize.y = 0;
85  SetDefaultLineWidth( 100 * aIusPerDecimil ); // Arbitrary default
86 }
87 
88 
89 void GERBER_PLOTTER::SetGerberCoordinatesFormat( int aResolution, bool aUseInches )
90 {
91  m_gerberUnitInch = aUseInches;
92  m_gerberUnitFmt = aResolution;
93 
94  iuPerDeviceUnit = pow( 10.0, m_gerberUnitFmt ) / ( m_IUsPerDecimil * 10000.0 );
95 
96  if( ! m_gerberUnitInch )
97  iuPerDeviceUnit *= 25.4; // gerber output in mm
98 }
99 
100 
101 void GERBER_PLOTTER::emitDcode( const DPOINT& pt, int dcode )
102 {
103 
104  fprintf( outputFile, "X%dY%dD%02d*\n",
105  KiROUND( pt.x ), KiROUND( pt.y ), dcode );
106 }
107 
108 
110 {
111  // disable a Gerber net attribute (exists only in X2 with net attributes mode).
112  if( m_objectAttributesDictionnary.empty() ) // No net attribute or not X2 mode
113  return;
114 
115  // Remove all net attributes from object attributes dictionnary
116  fputs( "%TD*%\n", outputFile );
117 
119 }
120 
121 
122 void GERBER_PLOTTER::StartBlock( void* aData )
123 {
124  // Currently, it is the same as EndBlock(): clear all aperture net attributes
125  EndBlock( aData );
126 }
127 
128 
129 void GERBER_PLOTTER::EndBlock( void* aData )
130 {
131  // Remove all net attributes from object attributes dictionnary
133 }
134 
135 
137 {
138  // print a Gerber net attribute record.
139  // it is added to the object attributes dictionnary
140  // On file, only modified or new attributes are printed.
141  if( aData == NULL || !m_useX2Attributes || !m_useNetAttributes )
142  return;
143 
144  bool clearDict;
145  std::string short_attribute_string;
146 
147  if( !FormatNetAttribute( short_attribute_string, m_objectAttributesDictionnary,
148  aData, clearDict ) )
149  return;
150 
151  if( clearDict )
153 
154  if( !short_attribute_string.empty() )
155  fputs( short_attribute_string.c_str(), outputFile );
156 }
157 
158 
160 {
161  wxASSERT( outputFile );
162 
163  finalFile = outputFile; // the actual gerber file will be created later
164 
165  // Create a temporary filename to store gerber file
166  // note tmpfile() does not work under Vista and W7 in user mode
167  m_workFilename = filename + wxT(".tmp");
168  workFile = wxFopen( m_workFilename, wxT( "wt" ));
170  wxASSERT( outputFile );
171 
172  if( outputFile == NULL )
173  return false;
174 
175  for( unsigned ii = 0; ii < m_headerExtraLines.GetCount(); ii++ )
176  {
177  if( ! m_headerExtraLines[ii].IsEmpty() )
178  fprintf( outputFile, "%s\n", TO_UTF8( m_headerExtraLines[ii] ) );
179  }
180 
181  // Set coordinate format to 3.6 or 4.5 absolute, leading zero omitted
182  // the number of digits for the integer part of coordintes is needed
183  // in gerber format, but is not very important when omitting leading zeros
184  // It is fixed here to 3 (inch) or 4 (mm), but is not actually used
185  int leadingDigitCount = m_gerberUnitInch ? 3 : 4;
186 
187  fprintf( outputFile, "%%FSLAX%d%dY%d%d*%%\n",
188  leadingDigitCount, m_gerberUnitFmt,
189  leadingDigitCount, m_gerberUnitFmt );
190  fprintf( outputFile,
191  "G04 Gerber Fmt %d.%d, Leading zero omitted, Abs format (unit %s)*\n",
192  leadingDigitCount, m_gerberUnitFmt,
193  m_gerberUnitInch ? "inch" : "mm" );
194 
195  wxString Title = creator + wxT( " " ) + GetBuildVersion();
196  fprintf( outputFile, "G04 Created by KiCad (%s) date %s*\n",
197  TO_UTF8( Title ), TO_UTF8( DateAndTime() ) );
198 
199  /* Mass parameter: unit = INCHES/MM */
200  if( m_gerberUnitInch )
201  fputs( "%MOIN*%\n", outputFile );
202  else
203  fputs( "%MOMM*%\n", outputFile );
204 
205  // Be sure the usual dark polarity is selected:
206  fputs( "%LPD*%\n", outputFile );
207 
208  // Specify linear interpol (G01):
209  fputs( "G01*\n", outputFile );
210 
211  fputs( "G04 APERTURE LIST*\n", outputFile );
212  /* Select the default aperture */
214 
215  return true;
216 }
217 
218 
220 {
221  char line[1024];
222  wxString msg;
223 
224  wxASSERT( outputFile );
225 
226  /* Outfile is actually a temporary file i.e. workFile */
227  fputs( "M02*\n", outputFile );
228  fflush( outputFile );
229 
230  fclose( workFile );
231  workFile = wxFopen( m_workFilename, wxT( "rt" ));
232  wxASSERT( workFile );
234 
235  // Placement of apertures in RS274X
236  while( fgets( line, 1024, workFile ) )
237  {
238  fputs( line, outputFile );
239 
240  if( strcmp( strtok( line, "\n\r" ), "G04 APERTURE LIST*" ) == 0 )
241  {
243  fputs( "G04 APERTURE END LIST*\n", outputFile );
244  }
245  }
246 
247  fclose( workFile );
248  fclose( finalFile );
249  ::wxRemoveFile( m_workFilename );
250  outputFile = 0;
251 
252  return true;
253 }
254 
255 
257 {
258  defaultPenWidth = width;
259  currentAperture = apertures.end();
260 }
261 
262 
263 void GERBER_PLOTTER::SetCurrentLineWidth( int width, void* aData )
264 {
265  if( width == DO_NOT_SET_LINE_WIDTH )
266  return;
267 
268  int pen_width;
269 
270  if( width > 0 )
271  pen_width = width;
272  else
273  pen_width = defaultPenWidth;
274 
275  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
276  int aperture_attribute = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
277 
278  selectAperture( wxSize( pen_width, pen_width ), APERTURE::Plotting, aperture_attribute );
279  currentPenWidth = pen_width;
280 }
281 
282 
283 std::vector<APERTURE>::iterator GERBER_PLOTTER::getAperture( const wxSize& aSize,
284  APERTURE::APERTURE_TYPE aType, int aApertureAttribute )
285 {
286  int last_D_code = 9;
287 
288  // Search an existing aperture
289  std::vector<APERTURE>::iterator tool = apertures.begin();
290 
291  while( tool != apertures.end() )
292  {
293  last_D_code = tool->m_DCode;
294 
295  if( (tool->m_Type == aType) && (tool->m_Size == aSize) && (tool->m_ApertureAttribute == aApertureAttribute) )
296  return tool;
297 
298  ++tool;
299  }
300 
301  // Allocate a new aperture
302  APERTURE new_tool;
303  new_tool.m_Size = aSize;
304  new_tool.m_Type = aType;
305  new_tool.m_DCode = last_D_code + 1;
306  new_tool.m_ApertureAttribute = aApertureAttribute;
307 
308  apertures.push_back( new_tool );
309 
310  return apertures.end() - 1;
311 }
312 
313 
314 void GERBER_PLOTTER::selectAperture( const wxSize& aSize,
316  int aApertureAttribute )
317 {
318  bool change = ( currentAperture == apertures.end() ) ||
319  ( currentAperture->m_Type != aType ) ||
320  ( currentAperture->m_Size != aSize );
321 
323  aApertureAttribute = 0;
324  else
325  change = change || ( currentAperture->m_ApertureAttribute != aApertureAttribute );
326 
327  if( change )
328  {
329  // Pick an existing aperture or create a new one
330  currentAperture = getAperture( aSize, aType, aApertureAttribute );
331  fprintf( outputFile, "D%d*\n", currentAperture->m_DCode );
332  }
333 }
334 
335 
337 {
338  wxASSERT( outputFile );
339  char cbuf[1024];
340 
341  // Init
342  for( std::vector<APERTURE>::iterator tool = apertures.begin();
343  tool != apertures.end(); ++tool )
344  {
345  // apertude sizes are in inch or mm, regardless the
346  // coordinates format
347  double fscale = 0.0001 * plotScale / m_IUsPerDecimil; // inches
348 
349  if(! m_gerberUnitInch )
350  fscale *= 25.4; // size in mm
351 
352  int attribute = tool->m_ApertureAttribute;
353 
354  if( attribute != m_apertureAttribute )
357 
358  char* text = cbuf + sprintf( cbuf, "%%ADD%d", tool->m_DCode );
359 
360  /* Please note: the Gerber specs for mass parameters say that
361  exponential syntax is *not* allowed and the decimal point should
362  also be always inserted. So the %g format is ruled out, but %f is fine
363  (the # modifier forces the decimal point). Sadly the %f formatter
364  can't remove trailing zeros but thats not a problem, since nothing
365  forbid it (the file is only slightly longer) */
366 
367  switch( tool->m_Type )
368  {
369  case APERTURE::Circle:
370  sprintf( text, "C,%#f*%%\n", tool->m_Size.x * fscale );
371  break;
372 
373  case APERTURE::Rect:
374  sprintf( text, "R,%#fX%#f*%%\n",
375  tool->m_Size.x * fscale,
376  tool->m_Size.y * fscale );
377  break;
378 
379  case APERTURE::Plotting:
380  sprintf( text, "C,%#f*%%\n", tool->m_Size.x * fscale );
381  break;
382 
383  case APERTURE::Oval:
384  sprintf( text, "O,%#fX%#f*%%\n",
385  tool->m_Size.x * fscale,
386  tool->m_Size.y * fscale );
387  break;
388  }
389 
390  fputs( cbuf, outputFile );
391 
392  m_apertureAttribute = attribute;
393 
394  // Currently reset the aperture attribute. Perhaps a better optimization
395  // is to store the last attribute
396  if( attribute )
397  {
398  fputs( "%TD*%\n", outputFile );
400  }
401 
402  }
403 }
404 
405 
406 void GERBER_PLOTTER::PenTo( const wxPoint& aPos, char plume )
407 {
408  wxASSERT( outputFile );
409  DPOINT pos_dev = userToDeviceCoordinates( aPos );
410 
411  switch( plume )
412  {
413  case 'Z':
414  break;
415 
416  case 'U':
417  emitDcode( pos_dev, 2 );
418  break;
419 
420  case 'D':
421  emitDcode( pos_dev, 1 );
422  }
423 
424  penState = plume;
425 }
426 
427 
428 void GERBER_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
429 {
430  std::vector< wxPoint > cornerList;
431 
432  // Build corners list
433  cornerList.push_back( p1 );
434  wxPoint corner(p1.x, p2.y);
435  cornerList.push_back( corner );
436  cornerList.push_back( p2 );
437  corner.x = p2.x;
438  corner.y = p1.y;
439  cornerList.push_back( corner );
440  cornerList.push_back( p1 );
441 
442  PlotPoly( cornerList, fill, width );
443 }
444 
445 
446 void GERBER_PLOTTER::Circle( const wxPoint& aCenter, int aDiameter, FILL_T aFill, int aWidth )
447 {
448  Arc( aCenter, 0, 3600, aDiameter / 2, aFill, aWidth );
449 }
450 
451 
452 void GERBER_PLOTTER::Arc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
453  int aRadius, FILL_T aFill, int aWidth )
454 {
455  SetCurrentLineWidth( aWidth );
456 
457  wxPoint start, end;
458  start.x = aCenter.x + KiROUND( cosdecideg( aRadius, aStAngle ) );
459  start.y = aCenter.y - KiROUND( sindecideg( aRadius, aStAngle ) );
460  MoveTo( start );
461  end.x = aCenter.x + KiROUND( cosdecideg( aRadius, aEndAngle ) );
462  end.y = aCenter.y - KiROUND( sindecideg( aRadius, aEndAngle ) );
463  DPOINT devEnd = userToDeviceCoordinates( end );
464  DPOINT devCenter = userToDeviceCoordinates( aCenter ) - userToDeviceCoordinates( start );
465 
466  fprintf( outputFile, "G75*\n" ); // Multiquadrant mode
467 
468  if( aStAngle < aEndAngle )
469  fprintf( outputFile, "G03" );
470  else
471  fprintf( outputFile, "G02" );
472 
473  fprintf( outputFile, "X%dY%dI%dJ%dD01*\n",
474  KiROUND( devEnd.x ), KiROUND( devEnd.y ),
475  KiROUND( devCenter.x ), KiROUND( devCenter.y ) );
476  fprintf( outputFile, "G01*\n" ); // Back to linear interp.
477 }
478 
479 
480 void GERBER_PLOTTER:: PlotPoly( const std::vector< wxPoint >& aCornerList,
481  FILL_T aFill, int aWidth, void * aData )
482 {
483  if( aCornerList.size() <= 1 )
484  return;
485 
486  // Gerber format does not know filled polygons with thick outline
487  // Therefore, to plot a filled polygon with outline having a thickness,
488  // one should plot outline as thick segments
489  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
490 
491  SetCurrentLineWidth( aWidth, gbr_metadata );
492 
493  if( gbr_metadata )
494  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
495 
496  if( aFill )
497  {
498  fputs( "G36*\n", outputFile );
499 
500  MoveTo( aCornerList[0] );
501 
502  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
503  LineTo( aCornerList[ii] );
504 
505  FinishTo( aCornerList[0] );
506  fputs( "G37*\n", outputFile );
507  }
508 
509  if( aWidth > 0 )
510  {
511  MoveTo( aCornerList[0] );
512 
513  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
514  LineTo( aCornerList[ii] );
515 
516  // Ensure the thick outline is closed for filled polygons
517  // (if not filled, could be only a polyline)
518  if( aFill && ( aCornerList[aCornerList.size()-1] != aCornerList[0] ) )
519  LineTo( aCornerList[0] );
520 
521  PenFinish();
522  }
523 }
524 
525 
526 void GERBER_PLOTTER::ThickSegment( const wxPoint& start, const wxPoint& end, int width,
527  EDA_DRAW_MODE_T tracemode, void* aData )
528 {
529  if( tracemode == FILLED )
530  {
531  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
532  SetCurrentLineWidth( width, gbr_metadata );
533 
534  if( gbr_metadata )
535  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
536 
537  MoveTo( start );
538  FinishTo( end );
539  }
540  else
541  {
543  segmentAsOval( start, end, width, tracemode );
544  }
545 }
546 
547 void GERBER_PLOTTER::ThickArc( const wxPoint& centre, double StAngle, double EndAngle,
548  int radius, int width, EDA_DRAW_MODE_T tracemode, void* aData )
549 {
550  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
551  SetCurrentLineWidth( width, gbr_metadata );
552 
553  if( gbr_metadata )
554  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
555 
556  if( tracemode == FILLED )
557  Arc( centre, StAngle, EndAngle, radius, NO_FILL, DO_NOT_SET_LINE_WIDTH );
558  else
559  {
561  Arc( centre, StAngle, EndAngle,
562  radius - ( width - currentPenWidth ) / 2,
564  Arc( centre, StAngle, EndAngle,
565  radius + ( width - currentPenWidth ) / 2, NO_FILL,
567  }
568 }
569 
570 
571 void GERBER_PLOTTER::ThickRect( const wxPoint& p1, const wxPoint& p2, int width,
572  EDA_DRAW_MODE_T tracemode, void* aData )
573 {
574  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
575  SetCurrentLineWidth( width, gbr_metadata );
576 
577  if( gbr_metadata )
578  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
579 
580  if( tracemode == FILLED )
581  Rect( p1, p2, NO_FILL, DO_NOT_SET_LINE_WIDTH );
582  else
583  {
585  wxPoint offsetp1( p1.x - (width - currentPenWidth) / 2,
586  p1.y - (width - currentPenWidth) / 2 );
587  wxPoint offsetp2( p2.x + (width - currentPenWidth) / 2,
588  p2.y + (width - currentPenWidth) / 2 );
589  Rect( offsetp1, offsetp2, NO_FILL, -1 );
590  offsetp1.x += (width - currentPenWidth);
591  offsetp1.y += (width - currentPenWidth);
592  offsetp2.x -= (width - currentPenWidth);
593  offsetp2.y -= (width - currentPenWidth);
594  Rect( offsetp1, offsetp2, NO_FILL, DO_NOT_SET_LINE_WIDTH );
595  }
596 }
597 
598 
599 void GERBER_PLOTTER::ThickCircle( const wxPoint& pos, int diametre, int width,
600  EDA_DRAW_MODE_T tracemode, void* aData )
601 {
602  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
603  SetCurrentLineWidth( width, gbr_metadata );
604 
605  if( gbr_metadata )
606  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
607 
608  if( tracemode == FILLED )
609  Circle( pos, diametre, NO_FILL, DO_NOT_SET_LINE_WIDTH );
610  else
611  {
613  Circle( pos, diametre - (width - currentPenWidth),
615  Circle( pos, diametre + (width - currentPenWidth),
617  }
618 }
619 
620 
621 void GERBER_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode, void* aData )
622 {
623  wxSize size( diametre, diametre );
624  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
625 
626  if( trace_mode == SKETCH )
627  {
629 
630  if( gbr_metadata )
631  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
632 
634  }
635  else
636  {
637  DPOINT pos_dev = userToDeviceCoordinates( pos );
638 
639  int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
640  selectAperture( size, APERTURE::Circle, aperture_attrib );
641 
642  if( gbr_metadata )
643  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
644 
645  emitDcode( pos_dev, 3 );
646  }
647 }
648 
649 
650 void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient,
651  EDA_DRAW_MODE_T trace_mode, void* aData )
652 {
653  wxASSERT( outputFile );
654  int x0, y0, x1, y1, delta;
655  wxSize size( aSize );
656  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
657 
658  /* Plot a flashed shape. */
659  if( ( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 )
660  && trace_mode == FILLED )
661  {
662  if( orient == 900 || orient == 2700 ) /* orientation turned 90 deg. */
663  std::swap( size.x, size.y );
664 
665  DPOINT pos_dev = userToDeviceCoordinates( pos );
666  int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
667  selectAperture( size, APERTURE::Oval, aperture_attrib );
668 
669  if( gbr_metadata )
670  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
671 
672  emitDcode( pos_dev, 3 );
673  }
674  else /* Plot pad as a segment. */
675  {
676  if( size.x > size.y )
677  {
678  std::swap( size.x, size.y );
679 
680  if( orient < 2700 )
681  orient += 900;
682  else
683  orient -= 2700;
684  }
685 
686  if( trace_mode == FILLED )
687  {
688  // TODO: use an aperture macro to declare the rotated pad
689  //
690 
691  // Flash a pad anchor, if a netlist attribute is set
692  if( aData )
693  FlashPadCircle( pos, size.x, trace_mode, aData );
694 
695  // The pad is reduced to an segment with dy > dx
696  delta = size.y - size.x;
697  x0 = 0;
698  y0 = -delta / 2;
699  x1 = 0;
700  y1 = delta / 2;
701  RotatePoint( &x0, &y0, orient );
702  RotatePoint( &x1, &y1, orient );
703  GBR_METADATA metadata;
704 
705  if( gbr_metadata )
706  {
707  metadata = *gbr_metadata;
709 
710  // Cleat .P attribute, only allowed for flashed items
711  wxString attrname( ".P" );
712  metadata.m_NetlistMetadata.ClearAttribute( &attrname );
713  }
714 
715  ThickSegment( wxPoint( pos.x + x0, pos.y + y0 ),
716  wxPoint( pos.x + x1, pos.y + y1 ),
717  size.x, trace_mode, &metadata );
718  }
719  else
720  {
721  sketchOval( pos, size, orient, -1 );
722  }
723  }
724 }
725 
726 
727 void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize,
728  double orient, EDA_DRAW_MODE_T trace_mode, void* aData )
729 
730 {
731  wxASSERT( outputFile );
732  wxSize size( aSize );
733  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
734 
735  // Plot as an aperture flash
736  switch( int( orient ) )
737  {
738  case 900:
739  case 2700: // rotation of 90 degrees or 270 swaps sizes
740  std::swap( size.x, size.y );
741 
742  // Pass through
743  case 0:
744  case 1800:
745  if( trace_mode == SKETCH )
746  {
748 
749  if( gbr_metadata )
750  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
751 
752  Rect( wxPoint( pos.x - (size.x - currentPenWidth) / 2,
753  pos.y - (size.y - currentPenWidth) / 2 ),
754  wxPoint( pos.x + (size.x - currentPenWidth) / 2,
755  pos.y + (size.y - currentPenWidth) / 2 ),
756  NO_FILL );
757  }
758  else
759  {
760  DPOINT pos_dev = userToDeviceCoordinates( pos );
761  int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
762  selectAperture( size, APERTURE::Rect, aperture_attrib );
763 
764  if( gbr_metadata )
765  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
766 
767  emitDcode( pos_dev, 3 );
768  }
769  break;
770 
771  default: // plot pad shape as polygon
772  {
773  // XXX to do: use an aperture macro to declare the rotated pad
774  wxPoint coord[4];
775  // coord[0] is assumed the lower left
776  // coord[1] is assumed the upper left
777  // coord[2] is assumed the upper right
778  // coord[3] is assumed the lower right
779 
780  /* Trace the outline. */
781  coord[0].x = -size.x/2; // lower left
782  coord[0].y = size.y/2;
783  coord[1].x = -size.x/2; // upper left
784  coord[1].y = -size.y/2;
785  coord[2].x = size.x/2; // upper right
786  coord[2].y = -size.y/2;
787  coord[3].x = size.x/2; // lower right
788  coord[3].y = size.y/2;
789 
790  FlashPadTrapez( pos, coord, orient, trace_mode, aData );
791  }
792  break;
793  }
794 }
795 
796 void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
797  int aCornerRadius, double aOrient,
798  EDA_DRAW_MODE_T aTraceMode, void* aData )
799 
800 {
801  // Currently, a Pad RoundRect is plotted as polygon.
802  // TODO: use Aperture macro and flash it
803  SHAPE_POLY_SET outline;
804  const int segmentToCircleCount = 64;
805  TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
806  aCornerRadius, segmentToCircleCount );
807 
808  std::vector< wxPoint > cornerList;
809  cornerList.reserve( segmentToCircleCount + 5 );
810  // TransformRoundRectToPolygon creates only one convex polygon
811  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
812 
813  for( int ii = 0; ii < poly.PointCount(); ++ii )
814  cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
815 
816  // Close polygon
817  cornerList.push_back( cornerList[0] );
818 
819  GBR_METADATA gbr_metadata;
820 
821  if( aData )
822  {
823  gbr_metadata = *static_cast<GBR_METADATA*>( aData );
825 
826  wxString attrname( ".P" );
827  gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
828  }
829 
830  PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
831 
832  // Now, flash a pad anchor, if a netlist attribute is set
833  // (remove me when a Aperture macro will be used)
834  if( aData && aTraceMode == FILLED )
835  {
836  int diameter = std::min( aSize.x, aSize.y );
837  FlashPadCircle( aPadPos, diameter, aTraceMode , aData );
838  }
839 }
840 
841 void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
842  SHAPE_POLY_SET* aPolygons,
843  EDA_DRAW_MODE_T aTraceMode, void* aData )
844 
845 {
846  // A Pad custom is plotted as polygon.
847 
848  // A flashed circle @aPadPos is added (anchor pad)
849  // However, because the anchor pad can be circle or rect, we use only
850  // a circle not bigger than the rect.
851  // the main purpose is to print a flashed DCode as pad anchor
852  FlashPadCircle( aPadPos, std::min( aSize.x, aSize.x ), aTraceMode, aData );
853  GBR_METADATA gbr_metadata;
854 
855  if( aData )
856  {
857  gbr_metadata = *static_cast<GBR_METADATA*>( aData );
859 
860  wxString attrname( ".P" );
861  gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
862  }
863 
864  std::vector< wxPoint > cornerList;
865 
866  for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
867  {
868  SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
869  cornerList.clear();
870 
871  for( int ii = 0; ii < poly.PointCount(); ++ii )
872  cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
873 
874  // Close polygon
875  cornerList.push_back( cornerList[0] );
876 
877  PlotPoly( cornerList, ( aTraceMode == FILLED ) ? FILLED_SHAPE : NO_FILL, USE_DEFAULT_LINE_WIDTH, &gbr_metadata );
878  }
879 }
880 
881 
882 void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners,
883  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData )
884 
885 {
886  // Currently, a Pad Trapezoid is plotted as polygon.
887  // TODO: use Aperture macro and flash it
888 
889  // polygon corners list
890  std::vector< wxPoint > cornerList;
891 
892  for( int ii = 0; ii < 4; ii++ )
893  cornerList.push_back( aCorners[ii] );
894 
895  // Now, flash a pad anchor, if a netlist attribute is set
896  // (remove me when a Aperture macro will be used)
897  if( aData && (aTrace_Mode==FILLED) )
898  {
899  // Calculate the radius of the circle inside the shape
900  // It is the smaller dist from shape pos to edges
901  int radius = INT_MAX;
902 
903  for( unsigned ii = 0, jj = cornerList.size()-1; ii < cornerList.size();
904  jj = ii, ii++ )
905  {
906  SEG segment( aCorners[ii], aCorners[jj] );
907  int dist = segment.LineDistance( VECTOR2I( 0, 0) );
908  radius = std::min( radius, dist );
909  }
910 
911  FlashPadCircle( aPadPos, radius*2, aTrace_Mode, aData );
912  }
913 
914  // Draw the polygon and fill the interior as required
915  for( unsigned ii = 0; ii < 4; ii++ )
916  {
917  RotatePoint( &cornerList[ii], aPadOrient );
918  cornerList[ii] += aPadPos;
919  }
920 
921  // Close the polygon
922  cornerList.push_back( cornerList[0] );
923  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
924 
925  GBR_METADATA metadata;
926 
927  if( gbr_metadata )
928  {
929  metadata = *gbr_metadata;
931  wxString attrname( ".P" );
932  metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
933  }
934 
936  PlotPoly( cornerList, aTrace_Mode==FILLED ? FILLED_SHAPE : NO_FILL, USE_DEFAULT_LINE_WIDTH, &metadata );
937 }
938 
939 
940 void GERBER_PLOTTER::Text( const wxPoint& aPos, const COLOR4D aColor,
941  const wxString& aText, double aOrient, const wxSize& aSize,
942  enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify,
943  int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed,
944  void* aData )
945 {
946  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
947 
948  if( gbr_metadata )
949  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
950 
951  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize,
952  aH_justify, aV_justify, aWidth, aItalic, aBold, aMultilineAllowed, aData );
953 }
954 
955 
956 void GERBER_PLOTTER::SetLayerPolarity( bool aPositive )
957 {
958  if( aPositive )
959  fprintf( outputFile, "%%LPD*%%\n" );
960  else
961  fprintf( outputFile, "%%LPC*%%\n" );
962 }
virtual void SetDefaultLineWidth(int width) override
Set the default line width.
std::vector< APERTURE >::iterator getAperture(const wxSize &aSize, APERTURE::APERTURE_TYPE aType, int aApertureAttribute)
Function getAperture returns a reference to the aperture which meets the size anf type of tool if the...
void FinishTo(const wxPoint &pos)
Definition: plot_common.h:241
virtual void FlashPadRoundRect(const wxPoint &aPadPos, const wxSize &aSize, int aCornerRadius, double aOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
Roundrect pad at the moment are not handled as aperture, since they require aperture macros TODO: alw...
void writeApertureList()
Generate the table of D codes.
void clearNetAttribute()
clear a Gerber net attribute record (clear object attribute dictionnary) and output the clear object ...
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:47
virtual void ThickSegment(const wxPoint &start, const wxPoint &end, int width, EDA_DRAW_MODE_T tracemode, void *aData) override
virtual void PenTo(const wxPoint &pos, char plume) override
moveto/lineto primitive, moves the 'pen' to the specified direction
void PenFinish()
Definition: plot_common.h:247
virtual void SetLayerPolarity(bool aPositive) override
Change the plot polarity and begin a new layer Used to 'scratch off' silk screen away from solder mas...
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
virtual void EndBlock(void *aData) override
calling this function allows to define the end of a group of drawing items the group is started by St...
APERTURE_TYPE m_Type
Definition: plot_common.h:977
int PointCount() const
Function PointCount()
wxSize m_Size
Definition: plot_common.h:976
bool m_useNetAttributes
Definition: plot_common.h:1200
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...
void formatNetAttribute(GBR_NETLIST_METADATA *aData)
print a Gerber net attribute object record.
virtual void FlashPadCustom(const wxPoint &aPadPos, const wxSize &aSize, SHAPE_POLY_SET *aPolygons, EDA_DRAW_MODE_T aTraceMode, void *aData) override
virtual function FlashPadCustom
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL) override
Gerber polygon: they can (and should) be filled with the appropriate G36/G37 sequence.
static const int dist[10][10]
Definition: dist.cpp:57
std::vector< APERTURE > apertures
Definition: plot_common.h:1192
void selectAperture(const wxSize &aSize, APERTURE::APERTURE_TYPE aType, int aApertureAttribute)
Pick an existing aperture or create a new one, matching the size, type and attributes.
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
char penState
Current pen state: 'U', 'D' or 'Z' (see PenTo)
Definition: plot_common.h:542
int OutlineCount() const
Returns the number of outlines in the set
double m_IUsPerDecimil
Definition: plot_common.h:519
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590
wxArrayString m_headerExtraLines
Definition: plot_common.h:552
virtual void FlashPadOval(const wxPoint &pos, const wxSize &size, double orient, EDA_DRAW_MODE_T trace_mode, void *aData) override
Filled oval flashes are handled as aperture in the 90 degree positions only.
wxPoint plotOffset
Plot offset (in IUs)
Definition: plot_common.h:525
static const int delta[8][2]
Definition: solve.cpp:112
virtual bool StartPlot() override
Function StartPlot Write GERBER header to file initialize global variable g_Plot_PlotOutputFile.
This file contains miscellaneous commonly used macros and functions.
virtual void ThickRect(const wxPoint &p1, const wxPoint &p2, int width, EDA_DRAW_MODE_T tracemode, void *aData) override
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, 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, bool aMultilineAllowed=false, void *aData=NULL)
Draws text with the plotter.
Definition: drawtxt.cpp:227
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, 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, bool aMultilineAllowed=false, void *aData=NULL) override
Draws text with the plotter.
virtual void FlashPadTrapez(const wxPoint &aPadPos, const wxPoint *aCorners, double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void *aData) override
Trapezoidal pad at the moment are never handled as aperture, since they require aperture macros TODO:...
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
void LineTo(const wxPoint &pos)
Definition: plot_common.h:236
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
static const int USE_DEFAULT_LINE_WIDTH
Definition: plot_common.h:95
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plot_common.h:529
virtual void SetCurrentLineWidth(int width, void *aData=NULL) override
Set the line width for the next drawing.
wxString GetBuildVersion()
Function GetBuildVersion Return the build version string.
Class SHAPE_POLY_SET.
Base window classes and related definitions.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
EDA_DRAW_MODE_T
Definition: eda_text.h:62
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Function LineDistance()
Definition: seg.h:337
bool FormatNetAttribute(std::string &aPrintedText, std::string &aLastNetAttributes, GBR_NETLIST_METADATA *aData, bool &aClearPreviousAttributes)
Generates the string to print to a gerber file, to set a net attribute for a graphic object...
double plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plot_common.h:513
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB GetApertureAttrib()
Common plot library Plot settings, and plotting engines (Postscript, Gerber, HPGL and DXF) ...
void emitDcode(const DPOINT &pt, int dcode)
Emit a D-Code record, using proper conversions to format a leading zero omitted gerber coordinate (fo...
virtual void ThickArc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, int width, EDA_DRAW_MODE_T tracemode, void *aData) override
virtual void FlashPadCircle(const wxPoint &pos, int diametre, EDA_DRAW_MODE_T trace_mode, void *aData) override
Filled circular flashes are stored as apertures.
aperture used for connected items like tracks (not vias)
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:54
void MoveTo(const wxPoint &pos)
Definition: plot_common.h:231
Definition: seg.h:37
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
bool m_useX2Attributes
Definition: plot_common.h:1198
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:311
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:302
virtual void StartBlock(void *aData) override
calling this function allows to define the beginning of a group of drawing items (used in X2 format w...
virtual void Arc(const wxPoint &aCenter, double aStAngle, double aEndAngle, int aRadius, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH) override
Generic fallback: arc rendered as a polyline.
int currentPenWidth
Definition: plot_common.h:540
int defaultPenWidth
true to generate a negative image (PS mode mainly)
Definition: plot_common.h:539
virtual bool EndPlot() override
Class SHAPE_LINE_CHAIN.
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plot_common.h:534
std::string m_objectAttributesDictionnary
Definition: plot_common.h:1178
The common library.
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false) override
Function SetGerberCoordinatesFormat selection of Gerber units and resolution (number of digits in man...
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:56
virtual void FlashPadRect(const wxPoint &pos, const wxSize &size, double orient, EDA_DRAW_MODE_T trace_mode, void *aData) override
Filled rect flashes are handled as aperture in the 0 90 180 or 270 degree orientation only and as pol...
void ClearAttribute(const wxString *aName)
remove the net attribute specified by aName If aName == NULL or empty, remove all attributes ...
VECTOR2I & Point(int aIndex)
Function Point()
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
wxString m_workFilename
Definition: plot_common.h:1185
GBR_NETLIST_METADATA m_NetlistMetadata
Basic classes for most KiCad items.
virtual void Circle(const wxPoint &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
int m_DCode
Definition: plot_common.h:978
int m_ApertureAttribute
Definition: plot_common.h:979
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plot_common.h:522
static const int DO_NOT_SET_LINE_WIDTH
Definition: plot_common.h:94
void segmentAsOval(const wxPoint &start, const wxPoint &end, int width, EDA_DRAW_MODE_T tracemode)
Cdonvert a thick segment and plot it as an oval.
wxString filename
Definition: plot_common.h:546
std::vector< APERTURE >::iterator currentAperture
Definition: plot_common.h:1193
virtual void ThickCircle(const wxPoint &pos, int diametre, int width, EDA_DRAW_MODE_T tracemode, void *aData) override
void sketchOval(const wxPoint &pos, const wxSize &size, double orient, int width)
wxString creator
Definition: plot_common.h:545
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:229
wxSize paperSize
Paper size in IU - not in mils.
Definition: plot_common.h:550
#define min(a, b)
Definition: auxiliary.h:85
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39