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