KiCad PCB EDA Suite
DXF_plotter.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
28 
29 #include <fctsys.h>
30 #include <trigo.h>
31 #include <eda_base_frame.h>
32 #include <base_struct.h>
33 #include <plotter.h>
34 #include <macros.h>
35 #include <kicad_string.h>
37 
42 static const double DXF_OBLIQUE_ANGLE = 15;
43 
44 /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
45 
46  - The primary colors (1 - 9)
47  - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
48  - Greys (251 - 255)
49 
50  There is *no* black... the white does it on paper, usually, and
51  anyway it depends on the plotter configuration, since DXF colors
52  are meant to be logical only (they represent *both* line color and
53  width); later version with plot styles only complicate the matter!
54 
55  As usual, brown and magenta/purple are difficult to place since
56  they are actually variations of other colors.
57  */
58 static const struct
59 {
60  const char *name;
61  int color;
63 {
64  { "BLACK", 7 }, // In DXF, color 7 is *both* white and black!
65  { "GRAY1", 251 },
66  { "GRAY2", 8 },
67  { "GRAY3", 9 },
68  { "WHITE", 7 },
69  { "LYELLOW", 51 },
70  { "BLUE1", 178 },
71  { "GREEN1", 98 },
72  { "CYAN1", 138 },
73  { "RED1", 18 },
74  { "MAGENTA1", 228 },
75  { "BROWN1", 58 },
76  { "BLUE2", 5 },
77  { "GREEN2", 3 },
78  { "CYAN2", 4 },
79  { "RED2", 1 },
80  { "MAGENTA2", 6 },
81  { "BROWN2", 54 },
82  { "BLUE3", 171 },
83  { "GREEN3", 91 },
84  { "CYAN3", 131 },
85  { "RED3", 11 },
86  { "MAGENTA3", 221 },
87  { "YELLOW3", 2 },
88  { "BLUE4", 5 },
89  { "GREEN4", 3 },
90  { "CYAN4", 4 },
91  { "RED4", 1 },
92  { "MAGENTA4", 6 },
93  { "YELLOW4", 2 }
94 };
95 
96 
97 static const char* getDXFLineType( PLOT_DASH_TYPE aType )
98 {
99  switch( aType )
100  {
103  return "CONTINUOUS";
105  return "DASHED";
106  case PLOT_DASH_TYPE::DOT:
107  return "DOTTED";
109  return "DASHDOT";
110  default:
111  wxFAIL_MSG( "Unhandled PLOT_DASH_TYPE" );
112  return "CONTINUOUS";
113  }
114 }
115 
116 
117 // A helper function to create a color name acceptable in DXF files
118 // DXF files do not use a RGB definition
119 static wxString getDXFColorName( COLOR4D aColor )
120 {
121  EDA_COLOR_T color = ColorFindNearest( int( aColor.r*255 ),
122  int( aColor.g*255 ),
123  int( aColor.b*255 ) );
124  wxString cname( dxf_layer[color].name );
125  return cname;
126 }
127 
128 
130 {
131  m_plotUnits = aUnit;
132 
133  switch( aUnit )
134  {
136  m_unitScalingFactor = 0.00254;
138  break;
139 
140  case DXF_UNITS::INCHES:
141  default:
142  m_unitScalingFactor = 0.0001;
144  }
145 }
146 
147 
153 void DXF_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
154  double aScale, bool aMirror )
155 {
156  plotOffset = aOffset;
157  plotScale = aScale;
158 
159  /* DXF paper is 'virtual' so there is no need of a paper size.
160  Also this way we can handle the aux origin which can be useful
161  (for example when aligning to a mechanical drawing) */
162  paperSize.x = 0;
163  paperSize.y = 0;
164 
165  /* Like paper size DXF units are abstract too. Anyway there is a
166  * system variable (MEASUREMENT) which will be set to 0 to indicate
167  * english units */
168  m_IUsPerDecimil = aIusPerDecimil;
169  iuPerDeviceUnit = 1.0 / aIusPerDecimil; // Gives a DXF in decimils
170  iuPerDeviceUnit *= GetUnitScaling(); // Get the scaling factor for the current units
171 
172  SetDefaultLineWidth( 0 ); // No line width on DXF
173  m_plotMirror = false; // No mirroring on DXF
175 }
176 
181 {
182  wxASSERT( outputFile );
183 
184  // DXF HEADER - Boilerplate
185  // Defines the minimum for drawing i.e. the angle system and the
186  // 4 linetypes (CONTINUOUS, DOTDASH, DASHED and DOTTED)
187  fprintf( outputFile,
188  " 0\n"
189  "SECTION\n"
190  " 2\n"
191  "HEADER\n"
192  " 9\n"
193  "$ANGBASE\n"
194  " 50\n"
195  "0.0\n"
196  " 9\n"
197  "$ANGDIR\n"
198  " 70\n"
199  "1\n"
200  " 9\n"
201  "$MEASUREMENT\n"
202  " 70\n"
203  "%u\n"
204  " 0\n"
205  "ENDSEC\n"
206  " 0\n"
207  "SECTION\n"
208  " 2\n"
209  "TABLES\n"
210  " 0\n"
211  "TABLE\n"
212  " 2\n"
213  "LTYPE\n"
214  " 70\n"
215  "4\n"
216  " 0\n"
217  "LTYPE\n"
218  " 5\n"
219  "40F\n"
220  " 2\n"
221  "CONTINUOUS\n"
222  " 70\n"
223  "0\n"
224  " 3\n"
225  "Solid line\n"
226  " 72\n"
227  "65\n"
228  " 73\n"
229  "0\n"
230  " 40\n"
231  "0.0\n"
232  " 0\n"
233  "LTYPE\n"
234  " 5\n"
235  "410\n"
236  " 2\n"
237  "DASHDOT\n"
238  " 70\n"
239  "0\n"
240  " 3\n"
241  "Dash Dot ____ _ ____ _\n"
242  " 72\n"
243  "65\n"
244  " 73\n"
245  "4\n"
246  " 40\n"
247  "2.0\n"
248  " 49\n"
249  "1.25\n"
250  " 49\n"
251  "-0.25\n"
252  " 49\n"
253  "0.25\n"
254  " 49\n"
255  "-0.25\n"
256  " 0\n"
257  "LTYPE\n"
258  " 5\n"
259  "411\n"
260  " 2\n"
261  "DASHED\n"
262  " 70\n"
263  "0\n"
264  " 3\n"
265  "Dashed __ __ __ __ __\n"
266  " 72\n"
267  "65\n"
268  " 73\n"
269  "2\n"
270  " 40\n"
271  "0.75\n"
272  " 49\n"
273  "0.5\n"
274  " 49\n"
275  "-0.25\n"
276  " 0\n"
277  "LTYPE\n"
278  " 5\n"
279  "43B\n"
280  " 2\n"
281  "DOTTED\n"
282  " 70\n"
283  "0\n"
284  " 3\n"
285  "Dotted . . . .\n"
286  " 72\n"
287  "65\n"
288  " 73\n"
289  "2\n"
290  " 40\n"
291  "0.2\n"
292  " 49\n"
293  "0.0\n"
294  " 49\n"
295  "-0.2\n"
296  " 0\n"
297  "ENDTAB\n",
299 
300  // Text styles table
301  // Defines 4 text styles, one for each bold/italic combination
302  fputs( " 0\n"
303  "TABLE\n"
304  " 2\n"
305  "STYLE\n"
306  " 70\n"
307  "4\n", outputFile );
308 
309  static const char *style_name[4] = {"KICAD", "KICADB", "KICADI", "KICADBI"};
310  for(int i = 0; i < 4; i++ )
311  {
312  fprintf( outputFile,
313  " 0\n"
314  "STYLE\n"
315  " 2\n"
316  "%s\n" // Style name
317  " 70\n"
318  "0\n" // Standard flags
319  " 40\n"
320  "0\n" // Non-fixed height text
321  " 41\n"
322  "1\n" // Width factor (base)
323  " 42\n"
324  "1\n" // Last height (mandatory)
325  " 50\n"
326  "%g\n" // Oblique angle
327  " 71\n"
328  "0\n" // Generation flags (default)
329  " 3\n"
330  // The standard ISO font (when kicad is build with it
331  // the dxf text in acad matches *perfectly*)
332  "isocp.shx\n", // Font name (when not bigfont)
333  // Apply a 15 degree angle to italic text
334  style_name[i], i < 2 ? 0 : DXF_OBLIQUE_ANGLE );
335  }
336 
337  EDA_COLOR_T numLayers = NBCOLORS;
338 
339  // If printing in monochrome, only output the black layer
340  if( !GetColorMode() )
341  numLayers = static_cast<EDA_COLOR_T>( 1 );
342 
343  // Layer table - one layer per color
344  fprintf( outputFile,
345  " 0\n"
346  "ENDTAB\n"
347  " 0\n"
348  "TABLE\n"
349  " 2\n"
350  "LAYER\n"
351  " 70\n"
352  "%d\n", numLayers );
353 
354  /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
355 
356  - The primary colors (1 - 9)
357  - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
358  - Greys (251 - 255)
359  */
360 
361  for( EDA_COLOR_T i = BLACK; i < numLayers; i = NextColor(i) )
362  {
363  fprintf( outputFile,
364  " 0\n"
365  "LAYER\n"
366  " 2\n"
367  "%s\n" // Layer name
368  " 70\n"
369  "0\n" // Standard flags
370  " 62\n"
371  "%d\n" // Color number
372  " 6\n"
373  "CONTINUOUS\n",// Linetype name
374  dxf_layer[i].name, dxf_layer[i].color );
375  }
376 
377  // End of layer table, begin entities
378  fputs( " 0\n"
379  "ENDTAB\n"
380  " 0\n"
381  "ENDSEC\n"
382  " 0\n"
383  "SECTION\n"
384  " 2\n"
385  "ENTITIES\n", outputFile );
386 
387  return true;
388 }
389 
390 
392 {
393  wxASSERT( outputFile );
394 
395  // DXF FOOTER
396  fputs( " 0\n"
397  "ENDSEC\n"
398  " 0\n"
399  "EOF\n", outputFile );
400  fclose( outputFile );
401  outputFile = NULL;
402 
403  return true;
404 }
405 
406 
411 {
412  if( ( colorMode )
413  || ( color == COLOR4D::BLACK )
414  || ( color == COLOR4D::WHITE ) )
415  {
417  }
418  else
420 }
421 
425 void DXF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
426 {
427  wxASSERT( outputFile );
428  MoveTo( p1 );
429  LineTo( wxPoint( p1.x, p2.y ) );
430  LineTo( wxPoint( p2.x, p2.y ) );
431  LineTo( wxPoint( p2.x, p1.y ) );
432  FinishTo( wxPoint( p1.x, p1.y ) );
433 }
434 
435 
442 void DXF_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, int width )
443 {
444  wxASSERT( outputFile );
445  double radius = userToDeviceSize( diameter / 2 );
446  DPOINT centre_dev = userToDeviceCoordinates( centre );
447  if( radius > 0 )
448  {
449  wxString cname = getDXFColorName( m_currentColor );
450 
451  if( !fill )
452  {
453  fprintf( outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
454  TO_UTF8( cname ),
455  centre_dev.x, centre_dev.y, radius );
456  }
457 
458  if( fill == FILLED_SHAPE )
459  {
460  double r = radius*0.5;
461  fprintf( outputFile, "0\nPOLYLINE\n");
462  fprintf( outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ));
463  fprintf( outputFile, "40\n%g\n41\n%g\n", radius, radius);
464  fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
465  fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
466  centre_dev.x-r, centre_dev.y );
467  fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
468  fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
469  centre_dev.x+r, centre_dev.y );
470  fprintf( outputFile, "0\nSEQEND\n");
471  }
472  }
473 }
474 
475 
482 void DXF_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
483  FILL_T aFill, int aWidth, void * aData )
484 {
485  if( aCornerList.size() <= 1 )
486  return;
487 
488  unsigned last = aCornerList.size() - 1;
489 
490  // Plot outlines with lines (thickness = 0) to define the polygon
491  if( aWidth <= 0 )
492  {
493  MoveTo( aCornerList[0] );
494 
495  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
496  LineTo( aCornerList[ii] );
497 
498  // Close polygon if 'fill' requested
499  if( aFill )
500  {
501  if( aCornerList[last] != aCornerList[0] )
502  LineTo( aCornerList[0] );
503  }
504 
505  PenFinish();
506 
507  return;
508  }
509 
510 
511  // if the polygon outline has thickness, and is not filled
512  // (i.e. is a polyline) plot outlines with thick segments
513  if( aWidth > 0 && !aFill )
514  {
515  MoveTo( aCornerList[0] );
516 
517  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
518  ThickSegment( aCornerList[ii-1], aCornerList[ii],
519  aWidth, FILLED, NULL );
520 
521  return;
522  }
523 
524  // The polygon outline has thickness, and is filled
525  // Build and plot the polygon which contains the initial
526  // polygon and its thick outline
527  SHAPE_POLY_SET bufferOutline;
528  SHAPE_POLY_SET bufferPolybase;
529 
530  bufferPolybase.NewOutline();
531 
532  // enter outline as polygon:
533  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
534  {
535  TransformSegmentToPolygon( bufferOutline,
536  aCornerList[ ii - 1 ], aCornerList[ ii ], GetPlotterArcHighDef(), aWidth );
537  }
538 
539  // enter the initial polygon:
540  for( unsigned ii = 0; ii < aCornerList.size(); ii++ )
541  {
542  bufferPolybase.Append( aCornerList[ii] );
543  }
544 
545  // Merge polygons to build the polygon which contains the initial
546  // polygon and its thick outline
547 
548  // create the outline which contains thick outline:
549  bufferPolybase.BooleanAdd( bufferOutline, SHAPE_POLY_SET::PM_FAST );
550  bufferPolybase.Fracture( SHAPE_POLY_SET::PM_FAST );
551 
552  if( bufferPolybase.OutlineCount() < 1 ) // should not happen
553  return;
554 
555  const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 );
556 
557  if( path.PointCount() < 2 ) // should not happen
558  return;
559 
560  // Now, output the final polygon to DXF file:
561  last = path.PointCount() - 1;
562  VECTOR2I point = path.CPoint( 0 );
563 
564  wxPoint startPoint( point.x, point.y );
565  MoveTo( startPoint );
566 
567  for( int ii = 1; ii < path.PointCount(); ii++ )
568  {
569  point = path.CPoint( ii );
570  LineTo( wxPoint( point.x, point.y ) );
571  }
572 
573  // Close polygon, if needed
574  point = path.CPoint( last );
575  wxPoint endPoint( point.x, point.y );
576 
577  if( endPoint != startPoint )
578  LineTo( startPoint );
579 
580  PenFinish();
581 }
582 
583 
584 void DXF_PLOTTER::PenTo( const wxPoint& pos, char plume )
585 {
586  wxASSERT( outputFile );
587  if( plume == 'Z' )
588  {
589  return;
590  }
591  DPOINT pos_dev = userToDeviceCoordinates( pos );
592  DPOINT pen_lastpos_dev = userToDeviceCoordinates( penLastpos );
593 
594  if( penLastpos != pos && plume == 'D' )
595  {
598  // DXF LINE
599  wxString cname = getDXFColorName( m_currentColor );
600  const char* lname = getDXFLineType( static_cast<PLOT_DASH_TYPE>( m_currentLineType ) );
601  fprintf( outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
602  TO_UTF8( cname ), lname,
603  pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
604  }
605  penLastpos = pos;
606 }
607 
608 
610 {
611  wxASSERT( aDashed >= PLOT_DASH_TYPE::FIRST_TYPE && aDashed <= PLOT_DASH_TYPE::LAST_TYPE );
612  m_currentLineType = aDashed;
613 }
614 
615 
616 void DXF_PLOTTER::ThickSegment( const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
617  EDA_DRAW_MODE_T aPlotMode, void* aData )
618 {
619  if( aPlotMode == SKETCH )
620  {
621  std::vector<wxPoint> cornerList;
622  SHAPE_POLY_SET outlineBuffer;
623  TransformOvalToPolygon( outlineBuffer, aStart, aEnd, aWidth, GetPlotterArcHighDef() );
624  const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline( 0 );
625 
626  cornerList.reserve( path.PointCount() );
627  for( int jj = 0; jj < path.PointCount(); jj++ )
628  cornerList.emplace_back( path.CPoint( jj ).x, path.CPoint( jj ).y );
629 
630  // Ensure the polygon is closed
631  if( cornerList[0] != cornerList[cornerList.size() - 1] )
632  cornerList.push_back( cornerList[0] );
633 
634  PlotPoly( cornerList, NO_FILL );
635  }
636  else
637  {
638  MoveTo( aStart );
639  FinishTo( aEnd );
640  }
641 }
642 
643 /* Plot an arc in DXF format
644  * Filling is not supported
645  */
646 void DXF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
647  FILL_T fill, int width )
648 {
649  wxASSERT( outputFile );
650 
651  if( radius <= 0 )
652  return;
653 
654  // In DXF, arcs are drawn CCW.
655  // In Kicad, arcs are CW or CCW
656  // If StAngle > EndAngle, it is CW. So transform it to CCW
657  if( StAngle > EndAngle )
658  {
659  std::swap( StAngle, EndAngle );
660  }
661 
662  DPOINT centre_dev = userToDeviceCoordinates( centre );
663  double radius_dev = userToDeviceSize( radius );
664 
665  // Emit a DXF ARC entity
666  wxString cname = getDXFColorName( m_currentColor );
667  fprintf( outputFile,
668  "0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
669  TO_UTF8( cname ),
670  centre_dev.x, centre_dev.y, radius_dev,
671  StAngle / 10.0, EndAngle / 10.0 );
672 }
673 
677 void DXF_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient,
678  EDA_DRAW_MODE_T trace_mode, void* aData )
679 {
680  wxASSERT( outputFile );
681  wxSize size( aSize );
682 
683  /* The chip is reduced to an oval tablet with size.y > size.x
684  * (Oval vertical orientation 0) */
685  if( size.x > size.y )
686  {
687  std::swap( size.x, size.y );
688  orient = AddAngles( orient, 900 );
689  }
690 
691  sketchOval( pos, size, orient, -1 );
692 }
693 
694 
699 void DXF_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre,
700  EDA_DRAW_MODE_T trace_mode, void* aData )
701 {
702  wxASSERT( outputFile );
703  Circle( pos, diametre, NO_FILL );
704 }
705 
706 
710 void DXF_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& padsize,
711  double orient, EDA_DRAW_MODE_T trace_mode, void* aData )
712 {
713  wxASSERT( outputFile );
714  wxSize size;
715  int ox, oy, fx, fy;
716 
717  size.x = padsize.x / 2;
718  size.y = padsize.y / 2;
719 
720  if( size.x < 0 )
721  size.x = 0;
722  if( size.y < 0 )
723  size.y = 0;
724 
725  // If a dimension is zero, the trace is reduced to 1 line
726  if( size.x == 0 )
727  {
728  ox = pos.x;
729  oy = pos.y - size.y;
730  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
731  fx = pos.x;
732  fy = pos.y + size.y;
733  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
734  MoveTo( wxPoint( ox, oy ) );
735  FinishTo( wxPoint( fx, fy ) );
736  return;
737  }
738  if( size.y == 0 )
739  {
740  ox = pos.x - size.x;
741  oy = pos.y;
742  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
743  fx = pos.x + size.x;
744  fy = pos.y;
745  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
746  MoveTo( wxPoint( ox, oy ) );
747  FinishTo( wxPoint( fx, fy ) );
748  return;
749  }
750 
751  ox = pos.x - size.x;
752  oy = pos.y - size.y;
753  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
754  MoveTo( wxPoint( ox, oy ) );
755 
756  fx = pos.x - size.x;
757  fy = pos.y + size.y;
758  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
759  LineTo( wxPoint( fx, fy ) );
760 
761  fx = pos.x + size.x;
762  fy = pos.y + size.y;
763  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
764  LineTo( wxPoint( fx, fy ) );
765 
766  fx = pos.x + size.x;
767  fy = pos.y - size.y;
768  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
769  LineTo( wxPoint( fx, fy ) );
770 
771  FinishTo( wxPoint( ox, oy ) );
772 }
773 
774 void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
775  int aCornerRadius, double aOrient,
776  EDA_DRAW_MODE_T aTraceMode, void* aData )
777 {
778  SHAPE_POLY_SET outline;
779  TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
780  aCornerRadius, 0.0, 0, GetPlotterArcHighDef() );
781 
782  // TransformRoundRectToPolygon creates only one convex polygon
783  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
784 
785  MoveTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
786 
787  for( int ii = 1; ii < poly.PointCount(); ++ii )
788  LineTo( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
789 
790  FinishTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
791 }
792 
793 void DXF_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
794  SHAPE_POLY_SET* aPolygons,
795  EDA_DRAW_MODE_T aTraceMode, void* aData )
796 {
797  for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
798  {
799  SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
800 
801  MoveTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
802 
803  for( int ii = 1; ii < poly.PointCount(); ++ii )
804  LineTo( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
805 
806  FinishTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
807  }
808 }
809 
810 
814 void DXF_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
815  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData )
816 {
817  wxASSERT( outputFile );
818  wxPoint coord[4]; /* coord actual corners of a trapezoidal trace */
819 
820  for( int ii = 0; ii < 4; ii++ )
821  {
822  coord[ii] = aCorners[ii];
823  RotatePoint( &coord[ii], aPadOrient );
824  coord[ii] += aPadPos;
825  }
826 
827  // Plot edge:
828  MoveTo( coord[0] );
829  LineTo( coord[1] );
830  LineTo( coord[2] );
831  LineTo( coord[3] );
832  FinishTo( coord[0] );
833 }
834 
835 
837  int aRadius, int aCornerCount,
838  double aOrient, EDA_DRAW_MODE_T aTraceMode, void* aData )
839 {
840  // Do nothing
841  wxASSERT( 0 );
842 }
843 
844 
853 bool containsNonAsciiChars( const wxString& string )
854 {
855  for( unsigned i = 0; i < string.length(); i++ )
856  {
857  wchar_t ch = string[i];
858  if( ch > 255 )
859  return true;
860  }
861  return false;
862 }
863 
864 void DXF_PLOTTER::Text( const wxPoint& aPos,
865  COLOR4D aColor,
866  const wxString& aText,
867  double aOrient,
868  const wxSize& aSize,
869  enum EDA_TEXT_HJUSTIFY_T aH_justify,
870  enum EDA_TEXT_VJUSTIFY_T aV_justify,
871  int aWidth,
872  bool aItalic,
873  bool aBold,
874  bool aMultilineAllowed,
875  void* aData )
876 {
877  // Fix me: see how to use DXF text mode for multiline texts
878  if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
879  aMultilineAllowed = false; // the text has only one line.
880 
881  bool processSuperSub = false;
882 
883  if( ( GetTextMarkupFlags() & ENABLE_SUBSCRIPT_MARKUP ) && aText.Contains( wxT( "#" ) ) )
884  processSuperSub = true;
885 
886  if( ( GetTextMarkupFlags() & ENABLE_SUPERSCRIPT_MARKUP ) && aText.Contains( wxT( "^" ) ) )
887  processSuperSub = true;
888 
889  if( textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed || processSuperSub )
890  {
891  // output text as graphics.
892  // Perhaps multiline texts could be handled as DXF text entity
893  // but I do not want spend time about this (JPC)
894  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
895  aWidth, aItalic, aBold, aMultilineAllowed );
896  }
897  else
898  {
899  /* Emit text as a text entity. This loses formatting and shape but it's
900  more useful as a CAD object */
901  DPOINT origin_dev = userToDeviceCoordinates( aPos );
902  SetColor( aColor );
903  wxString cname = getDXFColorName( m_currentColor );
904  DPOINT size_dev = userToDeviceSize( aSize );
905  int h_code = 0, v_code = 0;
906  switch( aH_justify )
907  {
909  h_code = 0;
910  break;
912  h_code = 1;
913  break;
915  h_code = 2;
916  break;
917  }
918  switch( aV_justify )
919  {
921  v_code = 3;
922  break;
924  v_code = 2;
925  break;
927  v_code = 1;
928  break;
929  }
930 
931  // Position, size, rotation and alignment
932  // The two alignment point usages is somewhat idiot (see the DXF ref)
933  // Anyway since we don't use the fit/aligned options, they're the same
934  fprintf( outputFile,
935  " 0\n"
936  "TEXT\n"
937  " 7\n"
938  "%s\n" // Text style
939  " 8\n"
940  "%s\n" // Layer name
941  " 10\n"
942  "%g\n" // First point X
943  " 11\n"
944  "%g\n" // Second point X
945  " 20\n"
946  "%g\n" // First point Y
947  " 21\n"
948  "%g\n" // Second point Y
949  " 40\n"
950  "%g\n" // Text height
951  " 41\n"
952  "%g\n" // Width factor
953  " 50\n"
954  "%g\n" // Rotation
955  " 51\n"
956  "%g\n" // Oblique angle
957  " 71\n"
958  "%d\n" // Mirror flags
959  " 72\n"
960  "%d\n" // H alignment
961  " 73\n"
962  "%d\n", // V alignment
963  aBold ? (aItalic ? "KICADBI" : "KICADB")
964  : (aItalic ? "KICADI" : "KICAD"),
965  TO_UTF8( cname ),
966  origin_dev.x, origin_dev.x,
967  origin_dev.y, origin_dev.y,
968  size_dev.y, fabs( size_dev.x / size_dev.y ),
969  aOrient / 10.0,
970  aItalic ? DXF_OBLIQUE_ANGLE : 0,
971  size_dev.x < 0 ? 2 : 0, // X mirror flag
972  h_code, v_code );
973 
974  /* There are two issue in emitting the text:
975  - Our overline character (~) must be converted to the appropriate
976  control sequence %%O or %%o
977  - Text encoding in DXF is more or less unspecified since depends on
978  the DXF declared version, the acad version reading it *and* some
979  system variables to be put in the header handled only by newer acads
980  Also before R15 unicode simply is not supported (you need to use
981  bigfonts which are a massive PITA). Common denominator solution:
982  use Latin1 (and however someone could choke on it, anyway). Sorry
983  for the extended latin people. If somewant want to try fixing this
984  recent version seems to use UTF-8 (and not UCS2 like the rest of
985  Windows)
986 
987  XXX Actually there is a *third* issue: older DXF formats are limited
988  to 255 bytes records (it was later raised to 2048); since I'm lazy
989  and text so long is not probable I just don't implement this rule.
990  If someone is interested in fixing this, you have to emit the first
991  partial lines with group code 3 (max 250 bytes each) and then finish
992  with a group code 1 (less than 250 bytes). The DXF refs explains it
993  in no more details...
994  */
995 
996  bool overlining = false;
997 
998  fputs( " 1\n", outputFile );
999 
1000  for( unsigned i = 0; i < aText.length(); i++ )
1001  {
1002  /* Here I do a bad thing: writing the output one byte at a time!
1003  but today I'm lazy and I have no idea on how to coerce a Unicode
1004  wxString to spit out latin1 encoded text ...
1005 
1006  Atleast stdio is *supposed* to do output buffering, so there is
1007  hope is not too slow */
1008  wchar_t ch = aText[i];
1009 
1010  if( ch > 255 )
1011  {
1012  // I can't encode this...
1013  putc( '?', outputFile );
1014  }
1015  else
1016  {
1017  if( ch == '~' )
1018  {
1019  if( ++i == aText.length() )
1020  break;
1021 
1022  ch = aText[i];
1023 
1024  if( ch == '~' )
1025  {
1026  // double ~ is really a ~ so go ahead and process the second one
1027 
1028  // so what about a triple ~? It could be a real ~ followed by an
1029  // overbar, or it could be an overbar followed by a real ~. The old
1030  // eeschema algorithm did the later so we will too....
1031  if( i + i < aText.length() && aText[i + 1] == '~' )
1032  {
1033  // eat the first two and toggle overbar
1034  ++i;
1035  fputs( overlining ? "%%o" : "%%O", outputFile );
1036  overlining = !overlining;
1037  }
1038  }
1039  else
1040  {
1041  // Handle the overline toggle
1042  fputs( overlining ? "%%o" : "%%O", outputFile );
1043  overlining = !overlining;
1044  }
1045  }
1046 
1047  putc( ch, outputFile );
1048  }
1049  }
1050  putc( '\n', outputFile );
1051  }
1052 }
1053 
void FinishTo(const wxPoint &pos)
Definition: plotter.h:283
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL) override
DXF polygon: doesn't fill it but at least it close the filled ones DXF does not know thick outline.
double m_unitScalingFactor
Definition: plotter.h:1550
EDA_COLOR_T
NOTE: EDA_COLOR_T is deprecated and is kept around for compatibility with legacy canvas.
Definition: colors.h:42
EDA_COLOR_T ColorFindNearest(const wxColour &aColor)
Find the nearest color match.
Definition: colors.cpp:96
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:44
void PenFinish()
Definition: plotter.h:289
int OutlineCount() const
Returns the number of outlines in the set
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.
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset union For aFastMode meaning, see function booleanOp
unsigned int m_measurementDirective
Definition: plotter.h:1551
static const struct @12 dxf_layer[NBCOLORS]
virtual void SetDash(PLOT_DASH_TYPE dashed) override
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the scale/position for the DXF plot The DXF engine doesn't support line widths and mirroring.
bool containsNonAsciiChars(const wxString &string)
Checks if a given string contains non-ASCII characters.
bool textAsLines
Definition: plotter.h:1545
static wxString getDXFColorName(COLOR4D aColor)
virtual void FlashPadTrapez(const wxPoint &aPadPos, const wxPoint *aCorners, double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
DXF trapezoidal pad: only sketch mode is supported.
DXF_UNITS m_plotUnits
Definition: plotter.h:1549
int color
Definition: DXF_plotter.cpp:61
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 PenTo(const wxPoint &pos, char plume) override
moveto/lineto primitive, moves the 'pen' to the specified direction
double g
Green component.
Definition: color4d.h:303
bool colorMode
Definition: plotter.h:600
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
COLOR4D m_currentColor
Definition: plotter.h:1546
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
double m_IUsPerDecimil
Definition: plotter.h:582
int PointCount() const
Function PointCount()
wxPoint plotOffset
Plot offset (in IUs)
Definition: plotter.h:588
wxPoint penLastpos
Last pen positions; set to -1,-1 when the pen is at rest.
Definition: plotter.h:607
double b
Blue component.
Definition: color4d.h:304
This file contains miscellaneous commonly used macros and functions.
double GetUnitScaling() const
Get the scale factor to apply to convert the device units to be in the currently set units.
Definition: plotter.h:1529
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: gr_text.cpp:232
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
virtual void ThickSegment(const wxPoint &start, const wxPoint &end, int width, EDA_DRAW_MODE_T tracemode, void *aData) override
const VECTOR2I & CPoint(int aIndex) const
Function Point()
static const double DXF_OBLIQUE_ANGLE
Oblique angle for DXF native text (I don't remember if 15 degrees is the ISO value....
Definition: DXF_plotter.cpp:42
void LineTo(const wxPoint &pos)
Definition: plotter.h:278
int GetTextMarkupFlags()
Definition: gr_text.cpp:55
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plotter.h:592
virtual bool StartPlot() override
Opens the DXF plot with a skeleton header.
#define NULL
void TransformOvalToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aStart, wxPoint aEnd, int aWidth, int aError)
convert a oblong shape to a polygon, using multiple segments It is similar to TransformRoundedEndsSeg...
T AddAngles(T a1, T2 a2)
Add two angles (keeping the result normalized). T2 is here.
Definition: trigo.h:304
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:59
virtual void FlashRegularPolygon(const wxPoint &aShapePos, int aDiameter, int aCornerCount, double aOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
Flash a regular polygon.
Base window classes and related definitions.
double plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plotter.h:576
virtual bool EndPlot() override
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
DXF rectangle: fill not supported.
virtual void FlashPadCircle(const wxPoint &pos, int diametre, EDA_DRAW_MODE_T trace_mode, void *aData) override
DXF round pad: always done in sketch mode; it could be filled but it isn't pretty if other kinds of p...
virtual DPOINT userToDeviceSize(const wxSize &size)
Modifies size according to the plotter scale factors (wxSize version, returns a DPOINT)
Definition: plotter.cpp:124
int NewOutline()
Creates a new empty polygon in the set and returns its index
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
virtual void Circle(const wxPoint &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
DXF circle: full functionality; it even does 'fills' drawing a circle with a dual-arc polyline wide a...
PLOT_DASH_TYPE
Enum for choosing dashed line type.
Definition: plotter.h:87
virtual void FlashPadRect(const wxPoint &pos, const wxSize &size, double orient, EDA_DRAW_MODE_T trace_mode, void *aData) override
DXF rectangular pad: alwayd done in sketch mode.
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:51
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aApproxErrorMax, int aMinSegPerCircleCount=16)
convert a rectangle with rounded corners and/or chamfered corners to a polygon Convert rounded corner...
void MoveTo(const wxPoint &pos)
Definition: plotter.h:273
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:99
static const char * getDXFLineType(PLOT_DASH_TYPE aType)
Definition: DXF_plotter.cpp:97
unsigned int GetMeasurementDirective() const
Get the correct value for the $MEASUREMENT field given the current units.
Definition: plotter.h:1539
const char * name
Definition: DXF_plotter.cpp:60
SHAPE_LINE_CHAIN.
virtual void SetDefaultLineWidth(int width) override
Set the default line width.
Definition: plotter.h:1444
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plotter.h:597
PLOT_DASH_TYPE m_currentLineType
Definition: plotter.h:1547
virtual void SetColor(COLOR4D color) override
The DXF exporter handles 'colors' as layers...
int GetPlotterArcHighDef() const
Definition: plotter.h:239
void TransformSegmentToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aStart, wxPoint aEnd, int aError, int aWidth)
Function TransformRoundedEndsSegmentToPolygon convert a segment with rounded ends to a polygon Conver...
Definition: colors.h:49
virtual void FlashPadOval(const wxPoint &pos, const wxSize &size, double orient, EDA_DRAW_MODE_T trace_mode, void *aData) override
DXF oval pad: always done in sketch mode.
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:42
Definition: colors.h:45
double r
Red component.
Definition: color4d.h:302
virtual void Arc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
Generic fallback: arc rendered as a polyline.
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plotter.h:585
Number of colors.
Definition: colors.h:75
void sketchOval(const wxPoint &pos, const wxSize &size, double orient, int width)
Definition: plotter.cpp:458
virtual void FlashPadRoundRect(const wxPoint &aPadPos, const wxSize &aSize, int aCornerRadius, double aOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
virtual function FlashPadRoundRect
wxSize paperSize
Paper size in IU - not in mils.
Definition: plotter.h:613
EDA_COLOR_T NextColor(EDA_COLOR_T &aColor)
Definition: colors.h:87
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)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40
bool GetColorMode() const
Definition: plotter.h:138