KiCad PCB EDA Suite
GERBER_plotter.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2018 KiCad Developers, see AUTHORS.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 <eda_base_frame.h>
34 #include <base_struct.h>
35 #include <common.h>
36 #include <plotter.h>
37 #include <macros.h>
38 #include <kicad_string.h>
40 
41 #include <build_version.h>
42 
43 #include <gbr_metadata.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  if( m_useX2Attributes )
117  fputs( "%TD*%\n", outputFile );
118  else
119  fputs( "G04 #@! TD*\n", outputFile );
120 
122 }
123 
124 
125 void GERBER_PLOTTER::StartBlock( void* aData )
126 {
127  // Currently, it is the same as EndBlock(): clear all aperture net attributes
128  EndBlock( aData );
129 }
130 
131 
132 void GERBER_PLOTTER::EndBlock( void* aData )
133 {
134  // Remove all net attributes from object attributes dictionnary
136 }
137 
138 
140 {
141  // print a Gerber net attribute record.
142  // it is added to the object attributes dictionnary
143  // On file, only modified or new attributes are printed.
144  if( aData == NULL )
145  return;
146 
147  bool useX1StructuredComment = false;
148 
149  if( !m_useX2Attributes )
150  useX1StructuredComment = true;
151  else if( !m_useNetAttributes )
152  return;
153 
154  bool clearDict;
155  std::string short_attribute_string;
156 
157  if( !FormatNetAttribute( short_attribute_string, m_objectAttributesDictionnary,
158  aData, clearDict, useX1StructuredComment ) )
159  return;
160 
161  if( clearDict )
163 
164  if( !short_attribute_string.empty() )
165  fputs( short_attribute_string.c_str(), outputFile );
166 }
167 
168 
170 {
171  wxASSERT( outputFile );
172 
173  finalFile = outputFile; // the actual gerber file will be created later
174 
175  // Create a temporary filename to store gerber file
176  // note tmpfile() does not work under Vista and W7 in user mode
177  m_workFilename = filename + wxT(".tmp");
178  workFile = wxFopen( m_workFilename, wxT( "wt" ));
180  wxASSERT( outputFile );
181 
182  if( outputFile == NULL )
183  return false;
184 
185  for( unsigned ii = 0; ii < m_headerExtraLines.GetCount(); ii++ )
186  {
187  if( ! m_headerExtraLines[ii].IsEmpty() )
188  fprintf( outputFile, "%s\n", TO_UTF8( m_headerExtraLines[ii] ) );
189  }
190 
191  // Set coordinate format to 3.6 or 4.5 absolute, leading zero omitted
192  // the number of digits for the integer part of coordintes is needed
193  // in gerber format, but is not very important when omitting leading zeros
194  // It is fixed here to 3 (inch) or 4 (mm), but is not actually used
195  int leadingDigitCount = m_gerberUnitInch ? 3 : 4;
196 
197  fprintf( outputFile, "%%FSLAX%d%dY%d%d*%%\n",
198  leadingDigitCount, m_gerberUnitFmt,
199  leadingDigitCount, m_gerberUnitFmt );
200  fprintf( outputFile,
201  "G04 Gerber Fmt %d.%d, Leading zero omitted, Abs format (unit %s)*\n",
202  leadingDigitCount, m_gerberUnitFmt,
203  m_gerberUnitInch ? "inch" : "mm" );
204 
205  wxString Title = creator + wxT( " " ) + GetBuildVersion();
206  fprintf( outputFile, "G04 Created by KiCad (%s) date %s*\n",
207  TO_UTF8( Title ), TO_UTF8( DateAndTime() ) );
208 
209  /* Mass parameter: unit = INCHES/MM */
210  if( m_gerberUnitInch )
211  fputs( "%MOIN*%\n", outputFile );
212  else
213  fputs( "%MOMM*%\n", outputFile );
214 
215  // Be sure the usual dark polarity is selected:
216  fputs( "%LPD*%\n", outputFile );
217 
218  // Specify linear interpol (G01):
219  fputs( "G01*\n", outputFile );
220 
221  fputs( "G04 APERTURE LIST*\n", outputFile );
222 
223  return true;
224 }
225 
226 
228 {
229  char line[1024];
230  wxString msg;
231 
232  wxASSERT( outputFile );
233 
234  /* Outfile is actually a temporary file i.e. workFile */
235  fputs( "M02*\n", outputFile );
236  fflush( outputFile );
237 
238  fclose( workFile );
239  workFile = wxFopen( m_workFilename, wxT( "rt" ));
240  wxASSERT( workFile );
242 
243  // Placement of apertures in RS274X
244  while( fgets( line, 1024, workFile ) )
245  {
246  fputs( line, outputFile );
247 
248  if( strcmp( strtok( line, "\n\r" ), "G04 APERTURE LIST*" ) == 0 )
249  {
251  fputs( "G04 APERTURE END LIST*\n", outputFile );
252  }
253  }
254 
255  fclose( workFile );
256  fclose( finalFile );
257  ::wxRemoveFile( m_workFilename );
258  outputFile = 0;
259 
260  return true;
261 }
262 
263 
265 {
266  defaultPenWidth = width;
267  currentAperture = apertures.end();
268 }
269 
270 
271 void GERBER_PLOTTER::SetCurrentLineWidth( int width, void* aData )
272 {
273  if( width == DO_NOT_SET_LINE_WIDTH )
274  return;
275 
276  int pen_width;
277 
278  if( width > 0 )
279  pen_width = width;
280  else
281  pen_width = defaultPenWidth;
282 
283  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
284  int aperture_attribute = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
285 
286  selectAperture( wxSize( pen_width, pen_width ), APERTURE::Plotting, aperture_attribute );
287  currentPenWidth = pen_width;
288 }
289 
290 
291 std::vector<APERTURE>::iterator GERBER_PLOTTER::getAperture( const wxSize& aSize,
292  APERTURE::APERTURE_TYPE aType, int aApertureAttribute )
293 {
294  int last_D_code = 9;
295 
296  // Search an existing aperture
297  std::vector<APERTURE>::iterator tool = apertures.begin();
298 
299  while( tool != apertures.end() )
300  {
301  last_D_code = tool->m_DCode;
302 
303  if( (tool->m_Type == aType) && (tool->m_Size == aSize) &&
304  (tool->m_ApertureAttribute == aApertureAttribute) )
305  return tool;
306 
307  ++tool;
308  }
309 
310  // Allocate a new aperture
311  APERTURE new_tool;
312  new_tool.m_Size = aSize;
313  new_tool.m_Type = aType;
314  new_tool.m_DCode = last_D_code + 1;
315  new_tool.m_ApertureAttribute = aApertureAttribute;
316 
317  apertures.push_back( new_tool );
318 
319  return apertures.end() - 1;
320 }
321 
322 
323 void GERBER_PLOTTER::selectAperture( const wxSize& aSize,
325  int aApertureAttribute )
326 {
327  bool change = ( currentAperture == apertures.end() ) ||
328  ( currentAperture->m_Type != aType ) ||
329  ( currentAperture->m_Size != aSize );
330 
332  aApertureAttribute = 0;
333  else
334  change = change || ( currentAperture->m_ApertureAttribute != aApertureAttribute );
335 
336  if( change )
337  {
338  // Pick an existing aperture or create a new one
339  currentAperture = getAperture( aSize, aType, aApertureAttribute );
340  fprintf( outputFile, "D%d*\n", currentAperture->m_DCode );
341  }
342 }
343 
344 
346 {
347  wxASSERT( outputFile );
348  char cbuf[1024];
349 
350  bool useX1StructuredComment = false;
351 
352  if( !m_useX2Attributes )
353  useX1StructuredComment = true;
354 
355  // Init
356  for( std::vector<APERTURE>::iterator tool = apertures.begin();
357  tool != apertures.end(); ++tool )
358  {
359  // apertude sizes are in inch or mm, regardless the
360  // coordinates format
361  double fscale = 0.0001 * plotScale / m_IUsPerDecimil; // inches
362 
363  if(! m_gerberUnitInch )
364  fscale *= 25.4; // size in mm
365 
366  int attribute = tool->m_ApertureAttribute;
367 
368  if( attribute != m_apertureAttribute )
369  {
372  useX1StructuredComment ).c_str(), outputFile );
373  }
374 
375  char* text = cbuf + sprintf( cbuf, "%%ADD%d", tool->m_DCode );
376 
377  /* Please note: the Gerber specs for mass parameters say that
378  exponential syntax is *not* allowed and the decimal point should
379  also be always inserted. So the %g format is ruled out, but %f is fine
380  (the # modifier forces the decimal point). Sadly the %f formatter
381  can't remove trailing zeros but thats not a problem, since nothing
382  forbid it (the file is only slightly longer) */
383 
384  switch( tool->m_Type )
385  {
386  case APERTURE::Circle:
387  sprintf( text, "C,%#f*%%\n", tool->m_Size.x * fscale );
388  break;
389 
390  case APERTURE::Rect:
391  sprintf( text, "R,%#fX%#f*%%\n",
392  tool->m_Size.x * fscale,
393  tool->m_Size.y * fscale );
394  break;
395 
396  case APERTURE::Plotting:
397  sprintf( text, "C,%#f*%%\n", tool->m_Size.x * fscale );
398  break;
399 
400  case APERTURE::Oval:
401  sprintf( text, "O,%#fX%#f*%%\n",
402  tool->m_Size.x * fscale,
403  tool->m_Size.y * fscale );
404  break;
405  }
406 
407  fputs( cbuf, outputFile );
408 
409  m_apertureAttribute = attribute;
410 
411  // Currently reset the aperture attribute. Perhaps a better optimization
412  // is to store the last attribute
413  if( attribute )
414  {
415  if( m_useX2Attributes )
416  fputs( "%TD*%\n", outputFile );
417  else
418  fputs( "G04 #@! TD*\n", outputFile );
419 
421  }
422 
423  }
424 }
425 
426 
427 void GERBER_PLOTTER::PenTo( const wxPoint& aPos, char plume )
428 {
429  wxASSERT( outputFile );
430  DPOINT pos_dev = userToDeviceCoordinates( aPos );
431 
432  switch( plume )
433  {
434  case 'Z':
435  break;
436 
437  case 'U':
438  emitDcode( pos_dev, 2 );
439  break;
440 
441  case 'D':
442  emitDcode( pos_dev, 1 );
443  }
444 
445  penState = plume;
446 }
447 
448 
449 void GERBER_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
450 {
451  std::vector< wxPoint > cornerList;
452 
453  // Build corners list
454  cornerList.push_back( p1 );
455  wxPoint corner(p1.x, p2.y);
456  cornerList.push_back( corner );
457  cornerList.push_back( p2 );
458  corner.x = p2.x;
459  corner.y = p1.y;
460  cornerList.push_back( corner );
461  cornerList.push_back( p1 );
462 
463  PlotPoly( cornerList, fill, width );
464 }
465 
466 
467 void GERBER_PLOTTER::Circle( const wxPoint& aCenter, int aDiameter, FILL_T aFill, int aWidth )
468 {
469  Arc( aCenter, 0, 3600, aDiameter / 2, aFill, aWidth );
470 }
471 
472 
473 void GERBER_PLOTTER::Arc( const wxPoint& aCenter, double aStAngle, double aEndAngle,
474  int aRadius, FILL_T aFill, int aWidth )
475 {
476  SetCurrentLineWidth( aWidth );
477 
478  wxPoint start, end;
479  start.x = aCenter.x + KiROUND( cosdecideg( aRadius, aStAngle ) );
480  start.y = aCenter.y - KiROUND( sindecideg( aRadius, aStAngle ) );
481  MoveTo( start );
482  end.x = aCenter.x + KiROUND( cosdecideg( aRadius, aEndAngle ) );
483  end.y = aCenter.y - KiROUND( sindecideg( aRadius, aEndAngle ) );
484  DPOINT devEnd = userToDeviceCoordinates( end );
485  DPOINT devCenter = userToDeviceCoordinates( aCenter ) - userToDeviceCoordinates( start );
486 
487  fprintf( outputFile, "G75*\n" ); // Multiquadrant mode
488 
489  if( aStAngle < aEndAngle )
490  fprintf( outputFile, "G03" );
491  else
492  fprintf( outputFile, "G02" );
493 
494  fprintf( outputFile, "X%dY%dI%dJ%dD01*\n",
495  KiROUND( devEnd.x ), KiROUND( devEnd.y ),
496  KiROUND( devCenter.x ), KiROUND( devCenter.y ) );
497  fprintf( outputFile, "G01*\n" ); // Back to linear interp.
498 }
499 
500 
501 void GERBER_PLOTTER:: PlotPoly( const std::vector< wxPoint >& aCornerList,
502  FILL_T aFill, int aWidth, void * aData )
503 {
504  if( aCornerList.size() <= 1 )
505  return;
506 
507  // Gerber format does not know filled polygons with thick outline
508  // Therefore, to plot a filled polygon with outline having a thickness,
509  // one should plot outline as thick segments
510  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
511 
512  SetCurrentLineWidth( aWidth, gbr_metadata );
513 
514  if( gbr_metadata )
515  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
516 
517  if( aFill )
518  {
519  fputs( "G36*\n", outputFile );
520 
521  MoveTo( aCornerList[0] );
522 
523  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
524  LineTo( aCornerList[ii] );
525 
526  FinishTo( aCornerList[0] );
527  fputs( "G37*\n", outputFile );
528  }
529 
530  if( aWidth > 0 )
531  {
532  MoveTo( aCornerList[0] );
533 
534  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
535  LineTo( aCornerList[ii] );
536 
537  // Ensure the thick outline is closed for filled polygons
538  // (if not filled, could be only a polyline)
539  if( aFill && ( aCornerList[aCornerList.size()-1] != aCornerList[0] ) )
540  LineTo( aCornerList[0] );
541 
542  PenFinish();
543  }
544 }
545 
546 
547 void GERBER_PLOTTER::ThickSegment( const wxPoint& start, const wxPoint& end, int width,
548  EDA_DRAW_MODE_T tracemode, void* aData )
549 {
550  if( tracemode == FILLED )
551  {
552  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
553  SetCurrentLineWidth( width, gbr_metadata );
554 
555  if( gbr_metadata )
556  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
557 
558  MoveTo( start );
559  FinishTo( end );
560  }
561  else
562  {
564  segmentAsOval( start, end, width, tracemode );
565  }
566 }
567 
568 void GERBER_PLOTTER::ThickArc( const wxPoint& centre, double StAngle, double EndAngle,
569  int radius, int width, EDA_DRAW_MODE_T tracemode, void* aData )
570 {
571  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
572  SetCurrentLineWidth( width, gbr_metadata );
573 
574  if( gbr_metadata )
575  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
576 
577  if( tracemode == FILLED )
578  Arc( centre, StAngle, EndAngle, radius, NO_FILL, DO_NOT_SET_LINE_WIDTH );
579  else
580  {
582  Arc( centre, StAngle, EndAngle,
583  radius - ( width - currentPenWidth ) / 2,
585  Arc( centre, StAngle, EndAngle,
586  radius + ( width - currentPenWidth ) / 2, NO_FILL,
588  }
589 }
590 
591 
592 void GERBER_PLOTTER::ThickRect( const wxPoint& p1, const wxPoint& p2, int width,
593  EDA_DRAW_MODE_T tracemode, void* aData )
594 {
595  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
596  SetCurrentLineWidth( width, gbr_metadata );
597 
598  if( gbr_metadata )
599  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
600 
601  if( tracemode == FILLED )
602  Rect( p1, p2, NO_FILL, DO_NOT_SET_LINE_WIDTH );
603  else
604  {
606  wxPoint offsetp1( p1.x - (width - currentPenWidth) / 2,
607  p1.y - (width - currentPenWidth) / 2 );
608  wxPoint offsetp2( p2.x + (width - currentPenWidth) / 2,
609  p2.y + (width - currentPenWidth) / 2 );
610  Rect( offsetp1, offsetp2, NO_FILL, -1 );
611  offsetp1.x += (width - currentPenWidth);
612  offsetp1.y += (width - currentPenWidth);
613  offsetp2.x -= (width - currentPenWidth);
614  offsetp2.y -= (width - currentPenWidth);
615  Rect( offsetp1, offsetp2, NO_FILL, DO_NOT_SET_LINE_WIDTH );
616  }
617 }
618 
619 
620 void GERBER_PLOTTER::ThickCircle( const wxPoint& pos, int diametre, int width,
621  EDA_DRAW_MODE_T tracemode, void* aData )
622 {
623  GBR_METADATA *gbr_metadata = static_cast<GBR_METADATA*>( aData );
624  SetCurrentLineWidth( width, gbr_metadata );
625 
626  if( gbr_metadata )
627  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
628 
629  if( tracemode == FILLED )
630  Circle( pos, diametre, NO_FILL, DO_NOT_SET_LINE_WIDTH );
631  else
632  {
634  Circle( pos, diametre - (width - currentPenWidth),
636  Circle( pos, diametre + (width - currentPenWidth),
638  }
639 }
640 
641 
642 void GERBER_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre, EDA_DRAW_MODE_T trace_mode, void* aData )
643 {
644  wxSize size( diametre, diametre );
645  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
646 
647  if( trace_mode == SKETCH )
648  {
650 
651  if( gbr_metadata )
652  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
653 
655  }
656  else
657  {
658  DPOINT pos_dev = userToDeviceCoordinates( pos );
659 
660  int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
661  selectAperture( size, APERTURE::Circle, aperture_attrib );
662 
663  if( gbr_metadata )
664  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
665 
666  emitDcode( pos_dev, 3 );
667  }
668 }
669 
670 
671 void GERBER_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient,
672  EDA_DRAW_MODE_T trace_mode, void* aData )
673 {
674  wxASSERT( outputFile );
675  wxSize size( aSize );
676  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
677 
678  /* Plot a flashed shape. */
679  if( ( orient == 0 || orient == 900 || orient == 1800 || orient == 2700 )
680  && trace_mode == FILLED )
681  {
682  if( orient == 900 || orient == 2700 ) /* orientation turned 90 deg. */
683  std::swap( size.x, size.y );
684 
685  DPOINT pos_dev = userToDeviceCoordinates( pos );
686  int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
687  selectAperture( size, APERTURE::Oval, aperture_attrib );
688 
689  if( gbr_metadata )
690  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
691 
692  emitDcode( pos_dev, 3 );
693  }
694  else /* Plot pad as a segment. */
695  {
696  if( size.x > size.y )
697  {
698  std::swap( size.x, size.y );
699 
700  if( orient < 2700 )
701  orient += 900;
702  else
703  orient -= 2700;
704  }
705 
706  if( trace_mode == FILLED )
707  {
708  // TODO: use an aperture macro to declare the rotated pad
709 
710  // Flash a pad anchor, if a netlist attribute is set
711  if( aData )
712  FlashPadCircle( pos, size.x, trace_mode, aData );
713 
714  // The pad is reduced to an segment with dy > dx
715  int delta = size.y - size.x;
716  int x0 = 0;
717  int y0 = -delta / 2;
718  int x1 = 0;
719  int y1 = delta / 2;
720  RotatePoint( &x0, &y0, orient );
721  RotatePoint( &x1, &y1, orient );
722  GBR_METADATA metadata;
723 
724  if( gbr_metadata )
725  {
726  metadata = *gbr_metadata;
727 
728  // If the pad is drawn on a copper layer,
729  // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
730  if( metadata.IsCopper() )
732 
733  // Clear .P attribute, only allowed for flashed items
734  wxString attrname( ".P" );
735  metadata.m_NetlistMetadata.ClearAttribute( &attrname );
736  }
737 
738  ThickSegment( wxPoint( pos.x + x0, pos.y + y0 ),
739  wxPoint( pos.x + x1, pos.y + y1 ),
740  size.x, trace_mode, &metadata );
741  }
742  else
743  {
744  sketchOval( pos, size, orient, -1 );
745  }
746  }
747 }
748 
749 
750 void GERBER_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& aSize,
751  double orient, EDA_DRAW_MODE_T trace_mode, void* aData )
752 
753 {
754  wxASSERT( outputFile );
755  wxSize size( aSize );
756  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
757 
758  // Plot as an aperture flash
759  switch( int( orient ) )
760  {
761  case 900:
762  case 2700: // rotation of 90 degrees or 270 swaps sizes
763  std::swap( size.x, size.y );
764  // Pass through
765  case 0:
766  case 1800:
767  if( trace_mode == SKETCH )
768  {
770 
771  if( gbr_metadata )
772  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
773 
774  Rect( wxPoint( pos.x - (size.x - currentPenWidth) / 2,
775  pos.y - (size.y - currentPenWidth) / 2 ),
776  wxPoint( pos.x + (size.x - currentPenWidth) / 2,
777  pos.y + (size.y - currentPenWidth) / 2 ),
779  }
780  else
781  {
782  DPOINT pos_dev = userToDeviceCoordinates( pos );
783  int aperture_attrib = gbr_metadata ? gbr_metadata->GetApertureAttrib() : 0;
784  selectAperture( size, APERTURE::Rect, aperture_attrib );
785 
786  if( gbr_metadata )
787  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
788 
789  emitDcode( pos_dev, 3 );
790  }
791  break;
792 
793  default: // plot pad shape as polygon
794  {
795  // XXX to do: use an aperture macro to declare the rotated pad
796  wxPoint coord[4];
797  // coord[0] is assumed the lower left
798  // coord[1] is assumed the upper left
799  // coord[2] is assumed the upper right
800  // coord[3] is assumed the lower right
801 
802  /* Trace the outline. */
803  coord[0].x = -size.x/2; // lower left
804  coord[0].y = size.y/2;
805  coord[1].x = -size.x/2; // upper left
806  coord[1].y = -size.y/2;
807  coord[2].x = size.x/2; // upper right
808  coord[2].y = -size.y/2;
809  coord[3].x = size.x/2; // lower right
810  coord[3].y = size.y/2;
811 
812  FlashPadTrapez( pos, coord, orient, trace_mode, aData );
813  }
814  break;
815  }
816 }
817 
818 void GERBER_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
819  int aCornerRadius, double aOrient,
820  EDA_DRAW_MODE_T aTraceMode, void* aData )
821 
822 {
823  GBR_METADATA gbr_metadata;
824 
825  if( aData )
826  {
827  gbr_metadata = *static_cast<GBR_METADATA*>( aData );
828  // If the pad is drawn on a copper layer,
829  // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
830  if( gbr_metadata.IsCopper() )
832 
833  wxString attrname( ".P" );
834  gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
835  }
836 
837  if( aTraceMode != FILLED )
839 
840  // Currently, a Pad RoundRect is plotted as polygon.
841  // TODO: use Aperture macro and flash it
842  SHAPE_POLY_SET outline;
843  const int segmentToCircleCount = 64;
844  TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
845  aCornerRadius, segmentToCircleCount );
846 
847  if( aTraceMode != FILLED )
848  outline.Inflate( -GetCurrentLineWidth()/2, 16 );
849 
850  std::vector< wxPoint > cornerList;
851  // TransformRoundRectToPolygon creates only one convex polygon
852  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
853  cornerList.reserve( poly.PointCount() + 1 );
854 
855  for( int ii = 0; ii < poly.PointCount(); ++ii )
856  cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
857 
858  // Close polygon
859  cornerList.push_back( cornerList[0] );
860 
861  PlotPoly( cornerList, aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL,
862  aTraceMode == FILLED ? 0 : GetCurrentLineWidth(), &gbr_metadata );
863 
864  // Now, flash a pad anchor, if a netlist attribute is set
865  // (remove me when a Aperture macro will be used)
866  if( aData && aTraceMode == FILLED )
867  {
868  int diameter = std::min( aSize.x, aSize.y );
869  FlashPadCircle( aPadPos, diameter, aTraceMode , aData );
870  }
871 }
872 
873 void GERBER_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
874  SHAPE_POLY_SET* aPolygons,
875  EDA_DRAW_MODE_T aTraceMode, void* aData )
876 
877 {
878  // A Pad custom is plotted as polygon.
879 
880  // A flashed circle @aPadPos is added (anchor pad)
881  // However, because the anchor pad can be circle or rect, we use only
882  // a circle not bigger than the rect.
883  // the main purpose is to print a flashed DCode as pad anchor
884  if( aTraceMode == FILLED )
885  FlashPadCircle( aPadPos, std::min( aSize.x, aSize.y ), aTraceMode, aData );
886 
887  GBR_METADATA gbr_metadata;
888 
889  if( aData )
890  {
891  gbr_metadata = *static_cast<GBR_METADATA*>( aData );
892  // If the pad is drawn on a copper layer,
893  // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
894  if( gbr_metadata.IsCopper() )
896 
897  wxString attrname( ".P" );
898  gbr_metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
899  }
900 
901  SHAPE_POLY_SET polyshape = *aPolygons;
902 
903  if( aTraceMode != FILLED )
904  {
906  polyshape.Inflate( -GetCurrentLineWidth()/2, 16 );
907  }
908 
909  std::vector< wxPoint > cornerList;
910 
911  for( int cnt = 0; cnt < polyshape.OutlineCount(); ++cnt )
912  {
913  SHAPE_LINE_CHAIN& poly = polyshape.Outline( cnt );
914 
915  cornerList.clear();
916 
917  for( int ii = 0; ii < poly.PointCount(); ++ii )
918  cornerList.push_back( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
919 
920  // Close polygon
921  cornerList.push_back( cornerList[0] );
922 
923  PlotPoly( cornerList,
924  aTraceMode == FILLED ? FILLED_SHAPE : NO_FILL,
925  aTraceMode == FILLED ? 0 : GetCurrentLineWidth(), &gbr_metadata );
926  }
927 }
928 
929 
930 void GERBER_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint* aCorners,
931  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData )
932 
933 {
934  // Currently, a Pad Trapezoid is plotted as polygon.
935  // TODO: use Aperture macro and flash it
936 
937  // polygon corners list
938  std::vector< wxPoint > cornerList;
939 
940  for( int ii = 0; ii < 4; ii++ )
941  cornerList.push_back( aCorners[ii] );
942 
943  // Now, flash a pad anchor, if a netlist attribute is set
944  // (remove me when a Aperture macro will be used)
945  if( aData && ( aTrace_Mode == FILLED ) )
946  {
947  // Calculate the radius of the circle inside the shape
948  // It is the smaller dist from shape pos to edges
949  int radius = INT_MAX;
950 
951  for( unsigned ii = 0, jj = cornerList.size()-1; ii < cornerList.size();
952  jj = ii, ii++ )
953  {
954  SEG segment( aCorners[ii], aCorners[jj] );
955  int dist = segment.LineDistance( VECTOR2I( 0, 0) );
956  radius = std::min( radius, dist );
957  }
958 
959  FlashPadCircle( aPadPos, radius*2, aTrace_Mode, aData );
960  }
961 
962  // Draw the polygon and fill the interior as required
963  for( unsigned ii = 0; ii < 4; ii++ )
964  {
965  RotatePoint( &cornerList[ii], aPadOrient );
966  cornerList[ii] += aPadPos;
967  }
968 
969  // Close the polygon
970  cornerList.push_back( cornerList[0] );
971  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
972 
973  GBR_METADATA metadata;
974 
975  if( gbr_metadata )
976  {
977  metadata = *gbr_metadata;
978  // If the pad is drawn on a copper layer,
979  // set attribute to GBR_APERTURE_ATTRIB_CONDUCTOR
980  if( metadata.IsCopper() )
982 
983  wxString attrname( ".P" );
984  metadata.m_NetlistMetadata.ClearAttribute( &attrname ); // not allowed on inner layers
985  }
986 
988  PlotPoly( cornerList, aTrace_Mode == FILLED ? FILLED_SHAPE : NO_FILL,
989  aTrace_Mode == FILLED ? 0 : GetCurrentLineWidth(),
990  &metadata );
991 }
992 
993 
994 void GERBER_PLOTTER::Text( const wxPoint& aPos, const COLOR4D aColor,
995  const wxString& aText, double aOrient, const wxSize& aSize,
996  enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify,
997  int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed,
998  void* aData )
999 {
1000  GBR_METADATA* gbr_metadata = static_cast<GBR_METADATA*>( aData );
1001 
1002  if( gbr_metadata )
1003  formatNetAttribute( &gbr_metadata->m_NetlistMetadata );
1004 
1005  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize,
1006  aH_justify, aV_justify, aWidth, aItalic, aBold, aMultilineAllowed, aData );
1007 }
1008 
1009 
1010 void GERBER_PLOTTER::SetLayerPolarity( bool aPositive )
1011 {
1012  if( aPositive )
1013  fprintf( outputFile, "%%LPD*%%\n" );
1014  else
1015  fprintf( outputFile, "%%LPC*%%\n" );
1016 }
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: plotter.h:251
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...
a class to handle special data (items attributes) during plot.
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:62
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 &#39;pen&#39; to the specified direction
void PenFinish()
Definition: plotter.h:257
virtual void FlashPadTrapez(const wxPoint &aPadPos, const wxPoint *aCorners, double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
Trapezoidal pad at the moment are never handled as aperture, since they require aperture macros TODO:...
static const int dist[10][10]
Definition: ar_matrix.cpp:320
virtual void SetLayerPolarity(bool aPositive) override
Change the plot polarity and begin a new layer Used to &#39;scratch off&#39; silk screen away from solder mas...
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
APERTURE_TYPE
Definition: plotter.h:995
virtual void EndBlock(void *aData) override
calling this function allows one to define the end of a group of drawing items the group is started b...
APERTURE_TYPE m_Type
Definition: plotter.h:1003
int PointCount() const
Function PointCount()
wxSize m_Size
Definition: plotter.h:1002
bool m_useNetAttributes
Definition: plotter.h:1226
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.
bool IsCopper()
Allowed attributes are not the same on board copper layers and on other layers Therefore a flag can b...
Definition: gbr_metadata.h:147
std::vector< APERTURE > apertures
Definition: plotter.h:1218
bool FormatNetAttribute(std::string &aPrintedText, std::string &aLastNetAttributes, GBR_NETLIST_METADATA *aData, bool &aClearPreviousAttributes, bool aUseX1StructuredComment)
Generates the string to print to a gerber file, to set a net attribute for a graphic object...
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:216
char penState
Current pen state: &#39;U&#39;, &#39;D&#39; or &#39;Z&#39; (see PenTo)
Definition: plotter.h:562
int OutlineCount() const
Returns the number of outlines in the set
this class handle info which can be added in a gerber file as attribute of an obtect the GBR_INFO_TYP...
double m_IUsPerDecimil
Definition: plotter.h:539
bool m_gerberUnitInch
Definition: plotter.h:1221
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
wxArrayString m_headerExtraLines
Definition: plotter.h:572
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: plotter.h:545
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.
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.
#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: plotter.h:246
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: plotter.h:102
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plotter.h:549
void Inflate(int aFactor, int aCircleSegmentsCount)
Performs outline inflation/deflation, using round corners.
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.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
EDA_DRAW_MODE_T
Definition: eda_text.h:77
int m_gerberUnitFmt
Definition: plotter.h:1222
int LineDistance(const VECTOR2I &aP, bool aDetermineSide=false) const
Function LineDistance()
Definition: seg.h:353
Base window classes and related definitions.
double plotScale
Plot scale - chosen by the user (even implicitly with &#39;fit in a4&#39;)
Definition: plotter.h:533
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()
Definition: gbr_metadata.h:124
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
FILE * finalFile
Definition: plotter.h:1210
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)
Definition: gbr_metadata.h:61
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:69
void MoveTo(const wxPoint &pos)
Definition: plotter.h:241
Definition: seg.h:36
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:96
static std::string FormatAttribute(GBR_APERTURE_ATTRIB aAttribute, bool aUseX1StructuredComment)
bool m_useX2Attributes
Definition: plotter.h:1224
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:354
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:345
virtual void StartBlock(void *aData) override
calling this function allows one to define the beginning of a group of drawing items (used in X2 form...
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: plotter.h:560
virtual int GetCurrentLineWidth() const
Definition: plotter.h:152
int defaultPenWidth
true to generate a negative image (PS mode mainly)
Definition: plotter.h:559
virtual bool EndPlot() override
Class SHAPE_LINE_CHAIN.
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plotter.h:554
std::string m_objectAttributesDictionnary
Definition: plotter.h:1204
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:54
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)
Definition: gbr_metadata.h:119
wxString m_workFilename
Definition: plotter.h:1211
GBR_NETLIST_METADATA m_NetlistMetadata
a item to handle object attribute:
Definition: gbr_metadata.h:158
int m_apertureAttribute
Definition: plotter.h:1207
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: plotter.h:1004
int m_ApertureAttribute
Definition: plotter.h:1005
FILE * workFile
Definition: plotter.h:1209
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plotter.h:542
static const int DO_NOT_SET_LINE_WIDTH
Definition: plotter.h:101
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.
Definition: plotter.cpp:387
wxString filename
Definition: plotter.h:566
std::vector< APERTURE >::iterator currentAperture
Definition: plotter.h:1219
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)
Definition: plotter.cpp:408
wxString creator
Definition: plotter.h:565
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:306
wxSize paperSize
Paper size in IU - not in mils.
Definition: plotter.h:570
#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