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