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