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