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 = COLOR4D::FindNearestLegacyColor( 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  m_plotMirror = false; // No mirroring on DXF
174 }
175 
180 {
181  wxASSERT( outputFile );
182 
183  // DXF HEADER - Boilerplate
184  // Defines the minimum for drawing i.e. the angle system and the
185  // 4 linetypes (CONTINUOUS, DOTDASH, DASHED and DOTTED)
186  fprintf( outputFile,
187  " 0\n"
188  "SECTION\n"
189  " 2\n"
190  "HEADER\n"
191  " 9\n"
192  "$ANGBASE\n"
193  " 50\n"
194  "0.0\n"
195  " 9\n"
196  "$ANGDIR\n"
197  " 70\n"
198  "1\n"
199  " 9\n"
200  "$MEASUREMENT\n"
201  " 70\n"
202  "%u\n"
203  " 0\n"
204  "ENDSEC\n"
205  " 0\n"
206  "SECTION\n"
207  " 2\n"
208  "TABLES\n"
209  " 0\n"
210  "TABLE\n"
211  " 2\n"
212  "LTYPE\n"
213  " 70\n"
214  "4\n"
215  " 0\n"
216  "LTYPE\n"
217  " 5\n"
218  "40F\n"
219  " 2\n"
220  "CONTINUOUS\n"
221  " 70\n"
222  "0\n"
223  " 3\n"
224  "Solid line\n"
225  " 72\n"
226  "65\n"
227  " 73\n"
228  "0\n"
229  " 40\n"
230  "0.0\n"
231  " 0\n"
232  "LTYPE\n"
233  " 5\n"
234  "410\n"
235  " 2\n"
236  "DASHDOT\n"
237  " 70\n"
238  "0\n"
239  " 3\n"
240  "Dash Dot ____ _ ____ _\n"
241  " 72\n"
242  "65\n"
243  " 73\n"
244  "4\n"
245  " 40\n"
246  "2.0\n"
247  " 49\n"
248  "1.25\n"
249  " 49\n"
250  "-0.25\n"
251  " 49\n"
252  "0.25\n"
253  " 49\n"
254  "-0.25\n"
255  " 0\n"
256  "LTYPE\n"
257  " 5\n"
258  "411\n"
259  " 2\n"
260  "DASHED\n"
261  " 70\n"
262  "0\n"
263  " 3\n"
264  "Dashed __ __ __ __ __\n"
265  " 72\n"
266  "65\n"
267  " 73\n"
268  "2\n"
269  " 40\n"
270  "0.75\n"
271  " 49\n"
272  "0.5\n"
273  " 49\n"
274  "-0.25\n"
275  " 0\n"
276  "LTYPE\n"
277  " 5\n"
278  "43B\n"
279  " 2\n"
280  "DOTTED\n"
281  " 70\n"
282  "0\n"
283  " 3\n"
284  "Dotted . . . .\n"
285  " 72\n"
286  "65\n"
287  " 73\n"
288  "2\n"
289  " 40\n"
290  "0.2\n"
291  " 49\n"
292  "0.0\n"
293  " 49\n"
294  "-0.2\n"
295  " 0\n"
296  "ENDTAB\n",
298 
299  // Text styles table
300  // Defines 4 text styles, one for each bold/italic combination
301  fputs( " 0\n"
302  "TABLE\n"
303  " 2\n"
304  "STYLE\n"
305  " 70\n"
306  "4\n", outputFile );
307 
308  static const char *style_name[4] = {"KICAD", "KICADB", "KICADI", "KICADBI"};
309  for(int i = 0; i < 4; i++ )
310  {
311  fprintf( outputFile,
312  " 0\n"
313  "STYLE\n"
314  " 2\n"
315  "%s\n" // Style name
316  " 70\n"
317  "0\n" // Standard flags
318  " 40\n"
319  "0\n" // Non-fixed height text
320  " 41\n"
321  "1\n" // Width factor (base)
322  " 42\n"
323  "1\n" // Last height (mandatory)
324  " 50\n"
325  "%g\n" // Oblique angle
326  " 71\n"
327  "0\n" // Generation flags (default)
328  " 3\n"
329  // The standard ISO font (when kicad is build with it
330  // the dxf text in acad matches *perfectly*)
331  "isocp.shx\n", // Font name (when not bigfont)
332  // Apply a 15 degree angle to italic text
333  style_name[i], i < 2 ? 0 : DXF_OBLIQUE_ANGLE );
334  }
335 
336  EDA_COLOR_T numLayers = NBCOLORS;
337 
338  // If printing in monochrome, only output the black layer
339  if( !GetColorMode() )
340  numLayers = static_cast<EDA_COLOR_T>( 1 );
341 
342  // Layer table - one layer per color
343  fprintf( outputFile,
344  " 0\n"
345  "ENDTAB\n"
346  " 0\n"
347  "TABLE\n"
348  " 2\n"
349  "LAYER\n"
350  " 70\n"
351  "%d\n", numLayers );
352 
353  /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
354 
355  - The primary colors (1 - 9)
356  - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
357  - Greys (251 - 255)
358  */
359 
360  wxASSERT( numLayers < NBCOLORS );
361 
362  for( EDA_COLOR_T i = BLACK; i < numLayers; i = static_cast<EDA_COLOR_T>( int( i ) + 1 ) )
363  {
364  fprintf( outputFile,
365  " 0\n"
366  "LAYER\n"
367  " 2\n"
368  "%s\n" // Layer name
369  " 70\n"
370  "0\n" // Standard flags
371  " 62\n"
372  "%d\n" // Color number
373  " 6\n"
374  "CONTINUOUS\n",// Linetype name
375  dxf_layer[i].name, dxf_layer[i].color );
376  }
377 
378  // End of layer table, begin entities
379  fputs( " 0\n"
380  "ENDTAB\n"
381  " 0\n"
382  "ENDSEC\n"
383  " 0\n"
384  "SECTION\n"
385  " 2\n"
386  "ENTITIES\n", outputFile );
387 
388  return true;
389 }
390 
391 
393 {
394  wxASSERT( outputFile );
395 
396  // DXF FOOTER
397  fputs( " 0\n"
398  "ENDSEC\n"
399  " 0\n"
400  "EOF\n", outputFile );
401  fclose( outputFile );
402  outputFile = NULL;
403 
404  return true;
405 }
406 
407 
412 {
413  if( ( colorMode )
414  || ( color == COLOR4D::BLACK )
415  || ( color == COLOR4D::WHITE ) )
416  {
418  }
419  else
421 }
422 
426 void DXF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
427 {
428  wxASSERT( outputFile );
429  MoveTo( p1 );
430  LineTo( wxPoint( p1.x, p2.y ) );
431  LineTo( wxPoint( p2.x, p2.y ) );
432  LineTo( wxPoint( p2.x, p1.y ) );
433  FinishTo( wxPoint( p1.x, p1.y ) );
434 }
435 
436 
443 void DXF_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, int width )
444 {
445  wxASSERT( outputFile );
446  double radius = userToDeviceSize( diameter / 2 );
447  DPOINT centre_dev = userToDeviceCoordinates( centre );
448  if( radius > 0 )
449  {
450  wxString cname = getDXFColorName( m_currentColor );
451 
452  if( !fill )
453  {
454  fprintf( outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
455  TO_UTF8( cname ),
456  centre_dev.x, centre_dev.y, radius );
457  }
458 
459  if( fill == FILLED_SHAPE )
460  {
461  double r = radius*0.5;
462  fprintf( outputFile, "0\nPOLYLINE\n");
463  fprintf( outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ));
464  fprintf( outputFile, "40\n%g\n41\n%g\n", radius, radius);
465  fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
466  fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
467  centre_dev.x-r, centre_dev.y );
468  fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
469  fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
470  centre_dev.x+r, centre_dev.y );
471  fprintf( outputFile, "0\nSEQEND\n");
472  }
473  }
474 }
475 
476 
483 void DXF_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
484  FILL_T aFill, int aWidth, void * aData )
485 {
486  if( aCornerList.size() <= 1 )
487  return;
488 
489  unsigned last = aCornerList.size() - 1;
490 
491  // Plot outlines with lines (thickness = 0) to define the polygon
492  if( aWidth <= 0 )
493  {
494  MoveTo( aCornerList[0] );
495 
496  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
497  LineTo( aCornerList[ii] );
498 
499  // Close polygon if 'fill' requested
500  if( aFill )
501  {
502  if( aCornerList[last] != aCornerList[0] )
503  LineTo( aCornerList[0] );
504  }
505 
506  PenFinish();
507 
508  return;
509  }
510 
511 
512  // if the polygon outline has thickness, and is not filled
513  // (i.e. is a polyline) plot outlines with thick segments
514  if( aWidth > 0 && !aFill )
515  {
516  MoveTo( aCornerList[0] );
517 
518  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
519  ThickSegment( aCornerList[ii-1], aCornerList[ii],
520  aWidth, FILLED, NULL );
521 
522  return;
523  }
524 
525  // The polygon outline has thickness, and is filled
526  // Build and plot the polygon which contains the initial
527  // polygon and its thick outline
528  SHAPE_POLY_SET bufferOutline;
529  SHAPE_POLY_SET bufferPolybase;
530 
531  bufferPolybase.NewOutline();
532 
533  // enter outline as polygon:
534  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
535  {
536  TransformOvalToPolygon( bufferOutline, aCornerList[ ii - 1 ], aCornerList[ ii ],
537  aWidth, GetPlotterArcHighDef() );
538  }
539 
540  // enter the initial polygon:
541  for( unsigned ii = 0; ii < aCornerList.size(); ii++ )
542  {
543  bufferPolybase.Append( aCornerList[ii] );
544  }
545 
546  // Merge polygons to build the polygon which contains the initial
547  // polygon and its thick outline
548 
549  // create the outline which contains thick outline:
550  bufferPolybase.BooleanAdd( bufferOutline, SHAPE_POLY_SET::PM_FAST );
551  bufferPolybase.Fracture( SHAPE_POLY_SET::PM_FAST );
552 
553  if( bufferPolybase.OutlineCount() < 1 ) // should not happen
554  return;
555 
556  const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 );
557 
558  if( path.PointCount() < 2 ) // should not happen
559  return;
560 
561  // Now, output the final polygon to DXF file:
562  last = path.PointCount() - 1;
563  VECTOR2I point = path.CPoint( 0 );
564 
565  wxPoint startPoint( point.x, point.y );
566  MoveTo( startPoint );
567 
568  for( int ii = 1; ii < path.PointCount(); ii++ )
569  {
570  point = path.CPoint( ii );
571  LineTo( wxPoint( point.x, point.y ) );
572  }
573 
574  // Close polygon, if needed
575  point = path.CPoint( last );
576  wxPoint endPoint( point.x, point.y );
577 
578  if( endPoint != startPoint )
579  LineTo( startPoint );
580 
581  PenFinish();
582 }
583 
584 
585 void DXF_PLOTTER::PenTo( const wxPoint& pos, char plume )
586 {
587  wxASSERT( outputFile );
588  if( plume == 'Z' )
589  {
590  return;
591  }
592  DPOINT pos_dev = userToDeviceCoordinates( pos );
593  DPOINT pen_lastpos_dev = userToDeviceCoordinates( penLastpos );
594 
595  if( penLastpos != pos && plume == 'D' )
596  {
599  // DXF LINE
600  wxString cname = getDXFColorName( m_currentColor );
601  const char* lname = getDXFLineType( static_cast<PLOT_DASH_TYPE>( m_currentLineType ) );
602  fprintf( outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
603  TO_UTF8( cname ), lname,
604  pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
605  }
606  penLastpos = pos;
607 }
608 
609 
611 {
612  wxASSERT( aDashed >= PLOT_DASH_TYPE::FIRST_TYPE && aDashed <= PLOT_DASH_TYPE::LAST_TYPE );
613  m_currentLineType = aDashed;
614 }
615 
616 
617 void DXF_PLOTTER::ThickSegment( const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
618  EDA_DRAW_MODE_T aPlotMode, void* aData )
619 {
620  if( aPlotMode == SKETCH )
621  {
622  std::vector<wxPoint> cornerList;
623  SHAPE_POLY_SET outlineBuffer;
624  TransformOvalToPolygon( outlineBuffer, aStart, aEnd, aWidth, GetPlotterArcHighDef() );
625  const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline( 0 );
626 
627  cornerList.reserve( path.PointCount() );
628  for( int jj = 0; jj < path.PointCount(); jj++ )
629  cornerList.emplace_back( path.CPoint( jj ).x, path.CPoint( jj ).y );
630 
631  // Ensure the polygon is closed
632  if( cornerList[0] != cornerList[cornerList.size() - 1] )
633  cornerList.push_back( cornerList[0] );
634 
635  PlotPoly( cornerList, NO_FILL );
636  }
637  else
638  {
639  MoveTo( aStart );
640  FinishTo( aEnd );
641  }
642 }
643 
644 /* Plot an arc in DXF format
645  * Filling is not supported
646  */
647 void DXF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
648  FILL_T fill, int width )
649 {
650  wxASSERT( outputFile );
651 
652  if( radius <= 0 )
653  return;
654 
655  // In DXF, arcs are drawn CCW.
656  // In Kicad, arcs are CW or CCW
657  // If StAngle > EndAngle, it is CW. So transform it to CCW
658  if( StAngle > EndAngle )
659  {
660  std::swap( StAngle, EndAngle );
661  }
662 
663  DPOINT centre_dev = userToDeviceCoordinates( centre );
664  double radius_dev = userToDeviceSize( radius );
665 
666  // Emit a DXF ARC entity
667  wxString cname = getDXFColorName( m_currentColor );
668  fprintf( outputFile,
669  "0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
670  TO_UTF8( cname ),
671  centre_dev.x, centre_dev.y, radius_dev,
672  StAngle / 10.0, EndAngle / 10.0 );
673 }
674 
678 void DXF_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient,
679  EDA_DRAW_MODE_T trace_mode, void* aData )
680 {
681  wxASSERT( outputFile );
682  wxSize size( aSize );
683 
684  /* The chip is reduced to an oval tablet with size.y > size.x
685  * (Oval vertical orientation 0) */
686  if( size.x > size.y )
687  {
688  std::swap( size.x, size.y );
689  orient = AddAngles( orient, 900 );
690  }
691 
692  sketchOval( pos, size, orient, -1 );
693 }
694 
695 
700 void DXF_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre,
701  EDA_DRAW_MODE_T trace_mode, void* aData )
702 {
703  wxASSERT( outputFile );
704  Circle( pos, diametre, NO_FILL );
705 }
706 
707 
711 void DXF_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& padsize,
712  double orient, EDA_DRAW_MODE_T trace_mode, void* aData )
713 {
714  wxASSERT( outputFile );
715  wxSize size;
716  int ox, oy, fx, fy;
717 
718  size.x = padsize.x / 2;
719  size.y = padsize.y / 2;
720 
721  if( size.x < 0 )
722  size.x = 0;
723  if( size.y < 0 )
724  size.y = 0;
725 
726  // If a dimension is zero, the trace is reduced to 1 line
727  if( size.x == 0 )
728  {
729  ox = pos.x;
730  oy = pos.y - size.y;
731  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
732  fx = pos.x;
733  fy = pos.y + size.y;
734  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
735  MoveTo( wxPoint( ox, oy ) );
736  FinishTo( wxPoint( fx, fy ) );
737  return;
738  }
739  if( size.y == 0 )
740  {
741  ox = pos.x - size.x;
742  oy = pos.y;
743  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
744  fx = pos.x + size.x;
745  fy = pos.y;
746  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
747  MoveTo( wxPoint( ox, oy ) );
748  FinishTo( wxPoint( fx, fy ) );
749  return;
750  }
751 
752  ox = pos.x - size.x;
753  oy = pos.y - size.y;
754  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
755  MoveTo( wxPoint( ox, oy ) );
756 
757  fx = pos.x - size.x;
758  fy = pos.y + size.y;
759  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
760  LineTo( wxPoint( fx, fy ) );
761 
762  fx = pos.x + size.x;
763  fy = pos.y + size.y;
764  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
765  LineTo( wxPoint( fx, fy ) );
766 
767  fx = pos.x + size.x;
768  fy = pos.y - size.y;
769  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
770  LineTo( wxPoint( fx, fy ) );
771 
772  FinishTo( wxPoint( ox, oy ) );
773 }
774 
775 void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
776  int aCornerRadius, double aOrient,
777  EDA_DRAW_MODE_T aTraceMode, void* aData )
778 {
779  SHAPE_POLY_SET outline;
780  TransformRoundChamferedRectToPolygon( outline, aPadPos, aSize, aOrient,
781  aCornerRadius, 0.0, 0, GetPlotterArcHighDef() );
782 
783  // TransformRoundRectToPolygon creates only one convex polygon
784  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
785 
786  MoveTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
787 
788  for( int ii = 1; ii < poly.PointCount(); ++ii )
789  LineTo( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
790 
791  FinishTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
792 }
793 
794 void DXF_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
795  SHAPE_POLY_SET* aPolygons,
796  EDA_DRAW_MODE_T aTraceMode, void* aData )
797 {
798  for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
799  {
800  SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
801 
802  MoveTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
803 
804  for( int ii = 1; ii < poly.PointCount(); ++ii )
805  LineTo( wxPoint( poly.CPoint( ii ).x, poly.CPoint( ii ).y ) );
806 
807  FinishTo( wxPoint( poly.CPoint( 0 ).x, poly.CPoint( 0 ).y ) );
808  }
809 }
810 
811 
815 void DXF_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
816  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData )
817 {
818  wxASSERT( outputFile );
819  wxPoint coord[4]; /* coord actual corners of a trapezoidal trace */
820 
821  for( int ii = 0; ii < 4; ii++ )
822  {
823  coord[ii] = aCorners[ii];
824  RotatePoint( &coord[ii], aPadOrient );
825  coord[ii] += aPadPos;
826  }
827 
828  // Plot edge:
829  MoveTo( coord[0] );
830  LineTo( coord[1] );
831  LineTo( coord[2] );
832  LineTo( coord[3] );
833  FinishTo( coord[0] );
834 }
835 
836 
838  int aRadius, int aCornerCount,
839  double aOrient, EDA_DRAW_MODE_T aTraceMode, void* aData )
840 {
841  // Do nothing
842  wxASSERT( 0 );
843 }
844 
845 
854 bool containsNonAsciiChars( const wxString& string )
855 {
856  for( unsigned i = 0; i < string.length(); i++ )
857  {
858  wchar_t ch = string[i];
859  if( ch > 255 )
860  return true;
861  }
862  return false;
863 }
864 
865 void DXF_PLOTTER::Text( const wxPoint& aPos,
866  COLOR4D aColor,
867  const wxString& aText,
868  double aOrient,
869  const wxSize& aSize,
870  enum EDA_TEXT_HJUSTIFY_T aH_justify,
871  enum EDA_TEXT_VJUSTIFY_T aV_justify,
872  int aWidth,
873  bool aItalic,
874  bool aBold,
875  bool aMultilineAllowed,
876  void* aData )
877 {
878  // Fix me: see how to use DXF text mode for multiline texts
879  if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
880  aMultilineAllowed = false; // the text has only one line.
881 
882  bool processSuperSub = aText.Contains( wxT( "^{" ) ) || aText.Contains( wxT( "_{" ) );
883 
884  if( m_textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed || processSuperSub )
885  {
886  // output text as graphics.
887  // Perhaps multiline texts could be handled as DXF text entity
888  // but I do not want spend time about this (JPC)
889  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
890  aWidth, aItalic, aBold, aMultilineAllowed );
891  }
892  else
893  {
894  /* Emit text as a text entity. This loses formatting and shape but it's
895  more useful as a CAD object */
896  DPOINT origin_dev = userToDeviceCoordinates( aPos );
897  SetColor( aColor );
898  wxString cname = getDXFColorName( m_currentColor );
899  DPOINT size_dev = userToDeviceSize( aSize );
900  int h_code = 0, v_code = 0;
901  switch( aH_justify )
902  {
904  h_code = 0;
905  break;
907  h_code = 1;
908  break;
910  h_code = 2;
911  break;
912  }
913  switch( aV_justify )
914  {
916  v_code = 3;
917  break;
919  v_code = 2;
920  break;
922  v_code = 1;
923  break;
924  }
925 
926  // Position, size, rotation and alignment
927  // The two alignment point usages is somewhat idiot (see the DXF ref)
928  // Anyway since we don't use the fit/aligned options, they're the same
929  fprintf( outputFile,
930  " 0\n"
931  "TEXT\n"
932  " 7\n"
933  "%s\n" // Text style
934  " 8\n"
935  "%s\n" // Layer name
936  " 10\n"
937  "%g\n" // First point X
938  " 11\n"
939  "%g\n" // Second point X
940  " 20\n"
941  "%g\n" // First point Y
942  " 21\n"
943  "%g\n" // Second point Y
944  " 40\n"
945  "%g\n" // Text height
946  " 41\n"
947  "%g\n" // Width factor
948  " 50\n"
949  "%g\n" // Rotation
950  " 51\n"
951  "%g\n" // Oblique angle
952  " 71\n"
953  "%d\n" // Mirror flags
954  " 72\n"
955  "%d\n" // H alignment
956  " 73\n"
957  "%d\n", // V alignment
958  aBold ? (aItalic ? "KICADBI" : "KICADB")
959  : (aItalic ? "KICADI" : "KICAD"),
960  TO_UTF8( cname ),
961  origin_dev.x, origin_dev.x,
962  origin_dev.y, origin_dev.y,
963  size_dev.y, fabs( size_dev.x / size_dev.y ),
964  aOrient / 10.0,
965  aItalic ? DXF_OBLIQUE_ANGLE : 0,
966  size_dev.x < 0 ? 2 : 0, // X mirror flag
967  h_code, v_code );
968 
969  /* There are two issue in emitting the text:
970  - Our overline character (~) must be converted to the appropriate
971  control sequence %%O or %%o
972  - Text encoding in DXF is more or less unspecified since depends on
973  the DXF declared version, the acad version reading it *and* some
974  system variables to be put in the header handled only by newer acads
975  Also before R15 unicode simply is not supported (you need to use
976  bigfonts which are a massive PITA). Common denominator solution:
977  use Latin1 (and however someone could choke on it, anyway). Sorry
978  for the extended latin people. If somewant want to try fixing this
979  recent version seems to use UTF-8 (and not UCS2 like the rest of
980  Windows)
981 
982  XXX Actually there is a *third* issue: older DXF formats are limited
983  to 255 bytes records (it was later raised to 2048); since I'm lazy
984  and text so long is not probable I just don't implement this rule.
985  If someone is interested in fixing this, you have to emit the first
986  partial lines with group code 3 (max 250 bytes each) and then finish
987  with a group code 1 (less than 250 bytes). The DXF refs explains it
988  in no more details...
989  */
990 
991  bool overlining = false;
992 
993  fputs( " 1\n", outputFile );
994 
995  for( unsigned i = 0; i < aText.length(); i++ )
996  {
997  /* Here I do a bad thing: writing the output one byte at a time!
998  but today I'm lazy and I have no idea on how to coerce a Unicode
999  wxString to spit out latin1 encoded text ...
1000 
1001  Atleast stdio is *supposed* to do output buffering, so there is
1002  hope is not too slow */
1003  wchar_t ch = aText[i];
1004 
1005  if( ch > 255 )
1006  {
1007  // I can't encode this...
1008  putc( '?', outputFile );
1009  }
1010  else
1011  {
1012  if( ch == '~' )
1013  {
1014  if( ++i == aText.length() )
1015  break;
1016 
1017  ch = aText[i];
1018 
1019  if( ch == '~' )
1020  {
1021  // double ~ is really a ~ so go ahead and process the second one
1022 
1023  // so what's a triple ~? It could be a real ~ followed by an overbar,
1024  // or it could be an overbar followed by a real ~. The old algorithm
1025  // did the former so we will too....
1026  }
1027  else
1028  {
1029  // Handle the overline toggle
1030  fputs( overlining ? "%%o" : "%%O", outputFile );
1031  overlining = !overlining;
1032  }
1033  }
1034 
1035  putc( ch, outputFile );
1036  }
1037  }
1038  putc( '\n', outputFile );
1039  }
1040 }
1041 
void FinishTo(const wxPoint &pos)
Definition: plotter.h:267
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:1580
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:48
void PenFinish()
Definition: plotter.h:273
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:1581
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.
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:1579
int color
Definition: DXF_plotter.cpp:61
bool m_textAsLines
Definition: plotter.h:1575
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:367
bool colorMode
Definition: plotter.h:589
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
Definition: color4d.h:44
COLOR4D m_currentColor
Definition: plotter.h:1576
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
double m_IUsPerDecimil
Definition: plotter.h:571
int PointCount() const
Function PointCount()
wxPoint plotOffset
Plot offset (in IUs)
Definition: plotter.h:577
wxPoint penLastpos
Definition: plotter.h:593
double b
Blue component.
Definition: color4d.h:368
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:1559
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:222
Number of colors.
Definition: color4d.h:74
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:100
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:262
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plotter.h:581
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:323
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:63
static const struct @8 dxf_layer[NBCOLORS]
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:565
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:125
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...
EDA_COLOR_T
Legacy color enumeration.
Definition: color4d.h:41
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:55
void MoveTo(const wxPoint &pos)
Definition: plotter.h:257
Definition: color4d.h:48
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:94
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:1569
const char * name
Definition: DXF_plotter.cpp:60
SHAPE_LINE_CHAIN.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plotter.h:586
PLOT_DASH_TYPE m_currentLineType
Definition: plotter.h:1577
virtual void SetColor(COLOR4D color) override
The DXF exporter handles 'colors' as layers...
int GetPlotterArcHighDef() const
Definition: plotter.h:223
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
double r
Red component.
Definition: color4d.h:366
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.
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aError)
convert a rectangle with rounded corners and/or chamfered corners to a polygon Convert rounded corner...
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plotter.h:574
void sketchOval(const wxPoint &pos, const wxSize &size, double orient, int width)
Definition: plotter.cpp:459
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
Definition: plotter.h:599
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:99
bool GetColorMode() const
Definition: plotter.h:144