KiCad PCB EDA Suite
common_plotDXF_functions.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27 
28 
29 #include <fctsys.h>
30 #include <gr_basic.h>
31 #include <trigo.h>
32 #include <wxstruct.h>
33 #include <base_struct.h>
34 #include <class_plotter.h>
35 #include <macros.h>
36 #include <kicad_string.h>
38 
43 static const double DXF_OBLIQUE_ANGLE = 15;
44 
45 /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
46 
47  - The primary colors (1 - 9)
48  - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
49  - Greys (251 - 255)
50 
51  There is *no* black... the white does it on paper, usually, and
52  anyway it depends on the plotter configuration, since DXF colors
53  are meant to be logical only (they represent *both* line color and
54  width); later version with plot styles only complicate the matter!
55 
56  As usual, brown and magenta/purple are difficult to place since
57  they are actually variations of other colors.
58  */
59 static const struct
60 {
61  const char *name;
62  int color;
64 {
65  { "BLACK", 7 }, // In DXF, color 7 is *both* white and black!
66  { "GRAY1", 251 },
67  { "GRAY2", 8 },
68  { "GRAY3", 9 },
69  { "WHITE", 7 },
70  { "LYELLOW", 51 },
71  { "BLUE1", 178 },
72  { "GREEN1", 98 },
73  { "CYAN1", 138 },
74  { "RED1", 18 },
75  { "MAGENTA1", 228 },
76  { "BROWN1", 58 },
77  { "BLUE2", 5 },
78  { "GREEN2", 3 },
79  { "CYAN2", 4 },
80  { "RED2", 1 },
81  { "MAGENTA2", 6 },
82  { "BROWN2", 54 },
83  { "BLUE3", 171 },
84  { "GREEN3", 91 },
85  { "CYAN3", 131 },
86  { "RED3", 11 },
87  { "MAGENTA3", 221 },
88  { "YELLOW3", 2 },
89  { "BLUE4", 5 },
90  { "GREEN4", 3 },
91  { "CYAN4", 4 },
92  { "RED4", 1 },
93  { "MAGENTA4", 6 },
94  { "YELLOW4", 2 }
95 };
96 
97 
98 static const char* getDXFLineType( PlotDashType aType )
99 {
100  switch( aType )
101  {
102  case PLOTDASHTYPE_SOLID: return "CONTINUOUS";
103  case PLOTDASHTYPE_DASH: return "DASHED";
104  case PLOTDASHTYPE_DOT: return "DOTTED";
105  case PLOTDASHTYPE_DASHDOT: return "DASHDOT";
106  }
107 
108  wxFAIL_MSG( "Unhandled PlotDashType" );
109  return "CONTINUOUS";
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( COLOR4D aColor )
116 {
117  EDA_COLOR_T color = ColorFindNearest( 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 
129 void DXF_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
130  double aScale, bool aMirror )
131 {
132  plotOffset = aOffset;
133  plotScale = aScale;
134 
135  /* DXF paper is 'virtual' so there is no need of a paper size.
136  Also this way we can handle the aux origin which can be useful
137  (for example when aligning to a mechanical drawing) */
138  paperSize.x = 0;
139  paperSize.y = 0;
140 
141  /* Like paper size DXF units are abstract too. Anyway there is a
142  * system variable (MEASUREMENT) which will be set to 1 to indicate
143  * metric units */
144  m_IUsPerDecimil = aIusPerDecimil;
145  iuPerDeviceUnit = 1.0 / aIusPerDecimil; // Gives a DXF in decimils
146  iuPerDeviceUnit *= 0.00254; // ... now in mm
147 
148  SetDefaultLineWidth( 0 ); // No line width on DXF
149  m_plotMirror = false; // No mirroring on DXF
151 }
152 
157 {
158  wxASSERT( outputFile );
159 
160  // DXF HEADER - Boilerplate
161  // Defines the minimum for drawing i.e. the angle system and the
162  // 4 linetypes (CONTINUOUS, DOTDASH, DASHED and DOTTED)
163  fputs( " 0\n"
164  "SECTION\n"
165  " 2\n"
166  "HEADER\n"
167  " 9\n"
168  "$ANGBASE\n"
169  " 50\n"
170  "0.0\n"
171  " 9\n"
172  "$ANGDIR\n"
173  " 70\n"
174  " 1\n"
175  " 9\n"
176  "$MEASUREMENT\n"
177  " 70\n"
178  "0\n"
179  " 0\n" // This means 'metric units'
180  "ENDSEC\n"
181  " 0\n"
182  "SECTION\n"
183  " 2\n"
184  "TABLES\n"
185  " 0\n"
186  "TABLE\n"
187  " 2\n"
188  "LTYPE\n"
189  " 70\n"
190  "4\n"
191  " 0\n"
192  "LTYPE\n"
193  " 5\n"
194  "40F\n"
195  " 2\n"
196  "CONTINUOUS\n"
197  " 70\n"
198  "0\n"
199  " 3\n"
200  "Solid line\n"
201  " 72\n"
202  "65\n"
203  " 73\n"
204  "0\n"
205  " 40\n"
206  "0.0\n"
207  " 0\n"
208  "LTYPE\n"
209  " 5\n"
210  "410\n"
211  " 2\n"
212  "DASHDOT\n"
213  " 70\n"
214  "0\n"
215  " 3\n"
216  "Dash Dot ____ _ ____ _\n"
217  " 72\n"
218  "65\n"
219  " 73\n"
220  "4\n"
221  " 40\n"
222  "2.0\n"
223  " 49\n"
224  "1.25\n"
225  " 49\n"
226  "-0.25\n"
227  " 49\n"
228  "0.25\n"
229  " 49\n"
230  "-0.25\n"
231  " 0\n"
232  "LTYPE\n"
233  " 5\n"
234  "411\n"
235  " 2\n"
236  "DASHED\n"
237  " 70\n"
238  "0\n"
239  " 3\n"
240  "Dashed __ __ __ __ __\n"
241  " 72\n"
242  "65\n"
243  " 73\n"
244  "2\n"
245  " 40\n"
246  "0.75\n"
247  " 49\n"
248  "0.5\n"
249  " 49\n"
250  "-0.25\n"
251  " 0\n"
252  "LTYPE\n"
253  " 5\n"
254  "43B\n"
255  " 2\n"
256  "DOTTED\n"
257  " 70\n"
258  "0\n"
259  " 3\n"
260  "Dotted . . . .\n"
261  " 72\n"
262  "65\n"
263  " 73\n"
264  "2\n"
265  " 40\n"
266  "0.2\n"
267  " 49\n"
268  "0.0\n"
269  " 49\n"
270  "-0.2\n"
271  " 0\n"
272  "ENDTAB\n",
273  outputFile );
274 
275  // Text styles table
276  // Defines 4 text styles, one for each bold/italic combination
277  fputs( " 0\n"
278  "TABLE\n"
279  " 2\n"
280  "STYLE\n"
281  " 70\n"
282  "4\n", outputFile );
283 
284  static const char *style_name[4] = {"KICAD", "KICADB", "KICADI", "KICADBI"};
285  for(int i = 0; i < 4; i++ )
286  {
287  fprintf( outputFile,
288  " 0\n"
289  "STYLE\n"
290  " 2\n"
291  "%s\n" // Style name
292  " 70\n"
293  "0\n" // Standard flags
294  " 40\n"
295  "0\n" // Non-fixed height text
296  " 41\n"
297  "1\n" // Width factor (base)
298  " 42\n"
299  "1\n" // Last height (mandatory)
300  " 50\n"
301  "%g\n" // Oblique angle
302  " 71\n"
303  "0\n" // Generation flags (default)
304  " 3\n"
305  // The standard ISO font (when kicad is build with it
306  // the dxf text in acad matches *perfectly*)
307  "isocp.shx\n", // Font name (when not bigfont)
308  // Apply a 15 degree angle to italic text
309  style_name[i], i < 2 ? 0 : DXF_OBLIQUE_ANGLE );
310  }
311 
312 
313  // Layer table - one layer per color
314  fprintf( outputFile,
315  " 0\n"
316  "ENDTAB\n"
317  " 0\n"
318  "TABLE\n"
319  " 2\n"
320  "LAYER\n"
321  " 70\n"
322  "%d\n", NBCOLORS );
323 
324  /* The layer/colors palette. The acad/DXF palette is divided in 3 zones:
325 
326  - The primary colors (1 - 9)
327  - An HSV zone (10-250, 5 values x 2 saturations x 10 hues
328  - Greys (251 - 255)
329  */
330 
331  for( EDA_COLOR_T i = BLACK; i < NBCOLORS; i = NextColor(i) )
332  {
333  fprintf( outputFile,
334  " 0\n"
335  "LAYER\n"
336  " 2\n"
337  "%s\n" // Layer name
338  " 70\n"
339  "0\n" // Standard flags
340  " 62\n"
341  "%d\n" // Color number
342  " 6\n"
343  "CONTINUOUS\n",// Linetype name
344  dxf_layer[i].name, dxf_layer[i].color );
345  }
346 
347  // End of layer table, begin entities
348  fputs( " 0\n"
349  "ENDTAB\n"
350  " 0\n"
351  "ENDSEC\n"
352  " 0\n"
353  "SECTION\n"
354  " 2\n"
355  "ENTITIES\n", outputFile );
356 
357  return true;
358 }
359 
360 
362 {
363  wxASSERT( outputFile );
364 
365  // DXF FOOTER
366  fputs( " 0\n"
367  "ENDSEC\n"
368  " 0\n"
369  "EOF\n", outputFile );
370  fclose( outputFile );
371  outputFile = NULL;
372 
373  return true;
374 }
375 
376 
381 {
382  if( ( colorMode )
383  || ( color == COLOR4D::BLACK )
384  || ( color == COLOR4D::WHITE ) )
385  {
387  }
388  else
390 }
391 
395 void DXF_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
396 {
397  wxASSERT( outputFile );
398  MoveTo( p1 );
399  LineTo( wxPoint( p1.x, p2.y ) );
400  LineTo( wxPoint( p2.x, p2.y ) );
401  LineTo( wxPoint( p2.x, p1.y ) );
402  FinishTo( wxPoint( p1.x, p1.y ) );
403 }
404 
405 
412 void DXF_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, int width )
413 {
414  wxASSERT( outputFile );
415  double radius = userToDeviceSize( diameter / 2 );
416  DPOINT centre_dev = userToDeviceCoordinates( centre );
417  if( radius > 0 )
418  {
419  wxString cname = getDXFColorName( m_currentColor );
420 
421  if( !fill )
422  {
423  fprintf( outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
424  TO_UTF8( cname ),
425  centre_dev.x, centre_dev.y, radius );
426  }
427 
428  if( fill == FILLED_SHAPE )
429  {
430  double r = radius*0.5;
431  fprintf( outputFile, "0\nPOLYLINE\n");
432  fprintf( outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ));
433  fprintf( outputFile, "40\n%g\n41\n%g\n", radius, radius);
434  fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
435  fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
436  centre_dev.x-r, centre_dev.y );
437  fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
438  fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
439  centre_dev.x+r, centre_dev.y );
440  fprintf( outputFile, "0\nSEQEND\n");
441  }
442  }
443 }
444 
445 
452 void DXF_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
453  FILL_T aFill, int aWidth, void * aData )
454 {
455  if( aCornerList.size() <= 1 )
456  return;
457 
458  unsigned last = aCornerList.size() - 1;
459 
460  // Plot outlines with lines (thickness = 0) to define the polygon
461  if( aWidth <= 0 )
462  {
463  MoveTo( aCornerList[0] );
464 
465  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
466  LineTo( aCornerList[ii] );
467 
468  // Close polygon if 'fill' requested
469  if( aFill )
470  {
471  if( aCornerList[last] != aCornerList[0] )
472  LineTo( aCornerList[0] );
473  }
474 
475  PenFinish();
476 
477  return;
478  }
479 
480 
481  // if the polygon outline has thickness, and is not filled
482  // (i.e. is a polyline) plot outlines with thick segments
483  if( aWidth > 0 && !aFill )
484  {
485  MoveTo( aCornerList[0] );
486 
487  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
488  ThickSegment( aCornerList[ii-1], aCornerList[ii],
489  aWidth, FILLED, NULL );
490 
491  return;
492  }
493 
494  // The polygon outline has thickness, and is filled
495  // Build and plot the polygon which contains the initial
496  // polygon and its thick outline
497  SHAPE_POLY_SET bufferOutline;
498  SHAPE_POLY_SET bufferPolybase;
499  const int circleToSegmentsCount = 16;
500 
501  bufferPolybase.NewOutline();
502 
503  // enter outline as polygon:
504  for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
505  {
507  aCornerList[ii-1], aCornerList[ii], circleToSegmentsCount, aWidth );
508  }
509 
510  // enter the initial polygon:
511  for( unsigned ii = 0; ii < aCornerList.size(); ii++ )
512  {
513  bufferPolybase.Append( aCornerList[ii] );
514  }
515 
516  // Merge polygons to build the polygon which contains the initial
517  // polygon and its thick outline
518 
519  // create the outline which contains thick outline:
520  bufferPolybase.BooleanAdd( bufferOutline, SHAPE_POLY_SET::PM_FAST );
521  bufferPolybase.Fracture( SHAPE_POLY_SET::PM_FAST );
522 
523  if( bufferPolybase.OutlineCount() < 1 ) // should not happen
524  return;
525 
526  const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 );
527 
528  if( path.PointCount() < 2 ) // should not happen
529  return;
530 
531  // Now, output the final polygon to DXF file:
532  last = path.PointCount() - 1;
533  VECTOR2I point = path.CPoint( 0 );
534 
535  wxPoint startPoint( point.x, point.y );
536  MoveTo( startPoint );
537 
538  for( int ii = 1; ii < path.PointCount(); ii++ )
539  {
540  point = path.CPoint( ii );
541  LineTo( wxPoint( point.x, point.y ) );
542  }
543 
544  // Close polygon, if needed
545  point = path.CPoint( last );
546  wxPoint endPoint( point.x, point.y );
547 
548  if( endPoint != startPoint )
549  LineTo( startPoint );
550 
551  PenFinish();
552 }
553 
554 
555 void DXF_PLOTTER::PenTo( const wxPoint& pos, char plume )
556 {
557  wxASSERT( outputFile );
558  if( plume == 'Z' )
559  {
560  return;
561  }
562  DPOINT pos_dev = userToDeviceCoordinates( pos );
563  DPOINT pen_lastpos_dev = userToDeviceCoordinates( penLastpos );
564 
565  if( penLastpos != pos && plume == 'D' )
566  {
567  wxASSERT( m_currentLineType >= 0 && m_currentLineType < 4 );
568  // DXF LINE
569  wxString cname = getDXFColorName( m_currentColor );
570  const char *lname = getDXFLineType( (PlotDashType) m_currentLineType );
571  fprintf( outputFile, "0\nLINE\n8\n%s\n6\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
572  TO_UTF8( cname ), lname,
573  pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
574  }
575  penLastpos = pos;
576 }
577 
578 
579 void DXF_PLOTTER::SetDash( int dashed )
580 {
581  wxASSERT( dashed >= 0 && dashed < 4 );
582  m_currentLineType = dashed;
583 }
584 
585 
586 void DXF_PLOTTER::ThickSegment( const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
587  EDA_DRAW_MODE_T aPlotMode, void* aData )
588 {
589  MoveTo( aStart );
590  FinishTo( aEnd );
591 }
592 
593 /* Plot an arc in DXF format
594  * Filling is not supported
595  */
596 void DXF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
597  FILL_T fill, int width )
598 {
599  wxASSERT( outputFile );
600 
601  if( radius <= 0 )
602  return;
603 
604  // In DXF, arcs are drawn CCW.
605  // In Kicad, arcs are CW or CCW
606  // If StAngle > EndAngle, it is CW. So transform it to CCW
607  if( StAngle > EndAngle )
608  {
609  std::swap( StAngle, EndAngle );
610  }
611 
612  DPOINT centre_dev = userToDeviceCoordinates( centre );
613  double radius_dev = userToDeviceSize( radius );
614 
615  // Emit a DXF ARC entity
616  wxString cname = getDXFColorName( m_currentColor );
617  fprintf( outputFile,
618  "0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
619  TO_UTF8( cname ),
620  centre_dev.x, centre_dev.y, radius_dev,
621  StAngle / 10.0, EndAngle / 10.0 );
622 }
623 
627 void DXF_PLOTTER::FlashPadOval( const wxPoint& pos, const wxSize& aSize, double orient,
628  EDA_DRAW_MODE_T trace_mode, void* aData )
629 {
630  wxASSERT( outputFile );
631  wxSize size( aSize );
632 
633  /* The chip is reduced to an oval tablet with size.y > size.x
634  * (Oval vertical orientation 0) */
635  if( size.x > size.y )
636  {
637  std::swap( size.x, size.y );
638  orient = AddAngles( orient, 900 );
639  }
640 
641  sketchOval( pos, size, orient, -1 );
642 }
643 
644 
649 void DXF_PLOTTER::FlashPadCircle( const wxPoint& pos, int diametre,
650  EDA_DRAW_MODE_T trace_mode, void* aData )
651 {
652  wxASSERT( outputFile );
653  Circle( pos, diametre, NO_FILL );
654 }
655 
656 
660 void DXF_PLOTTER::FlashPadRect( const wxPoint& pos, const wxSize& padsize,
661  double orient, EDA_DRAW_MODE_T trace_mode, void* aData )
662 {
663  wxASSERT( outputFile );
664  wxSize size;
665  int ox, oy, fx, fy;
666 
667  size.x = padsize.x / 2;
668  size.y = padsize.y / 2;
669 
670  if( size.x < 0 )
671  size.x = 0;
672  if( size.y < 0 )
673  size.y = 0;
674 
675  // If a dimension is zero, the trace is reduced to 1 line
676  if( size.x == 0 )
677  {
678  ox = pos.x;
679  oy = pos.y - size.y;
680  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
681  fx = pos.x;
682  fy = pos.y + size.y;
683  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
684  MoveTo( wxPoint( ox, oy ) );
685  FinishTo( wxPoint( fx, fy ) );
686  return;
687  }
688  if( size.y == 0 )
689  {
690  ox = pos.x - size.x;
691  oy = pos.y;
692  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
693  fx = pos.x + size.x;
694  fy = pos.y;
695  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
696  MoveTo( wxPoint( ox, oy ) );
697  FinishTo( wxPoint( fx, fy ) );
698  return;
699  }
700 
701  ox = pos.x - size.x;
702  oy = pos.y - size.y;
703  RotatePoint( &ox, &oy, pos.x, pos.y, orient );
704  MoveTo( wxPoint( ox, oy ) );
705 
706  fx = pos.x - size.x;
707  fy = pos.y + size.y;
708  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
709  LineTo( wxPoint( fx, fy ) );
710 
711  fx = pos.x + size.x;
712  fy = pos.y + size.y;
713  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
714  LineTo( wxPoint( fx, fy ) );
715 
716  fx = pos.x + size.x;
717  fy = pos.y - size.y;
718  RotatePoint( &fx, &fy, pos.x, pos.y, orient );
719  LineTo( wxPoint( fx, fy ) );
720 
721  FinishTo( wxPoint( ox, oy ) );
722 }
723 
724 void DXF_PLOTTER::FlashPadRoundRect( const wxPoint& aPadPos, const wxSize& aSize,
725  int aCornerRadius, double aOrient,
726  EDA_DRAW_MODE_T aTraceMode, void* aData )
727 {
728  SHAPE_POLY_SET outline;
729  const int segmentToCircleCount = 64;
730  TransformRoundRectToPolygon( outline, aPadPos, aSize, aOrient,
731  aCornerRadius, segmentToCircleCount );
732 
733  // TransformRoundRectToPolygon creates only one convex polygon
734  SHAPE_LINE_CHAIN& poly = outline.Outline( 0 );
735 
736  MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
737 
738  for( int ii = 1; ii < poly.PointCount(); ++ii )
739  LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
740 
741  FinishTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
742 }
743 
744 void DXF_PLOTTER::FlashPadCustom( const wxPoint& aPadPos, const wxSize& aSize,
745  SHAPE_POLY_SET* aPolygons,
746  EDA_DRAW_MODE_T aTraceMode, void* aData )
747 {
748  for( int cnt = 0; cnt < aPolygons->OutlineCount(); ++cnt )
749  {
750  SHAPE_LINE_CHAIN& poly = aPolygons->Outline( cnt );
751 
752  MoveTo( wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
753 
754  for( int ii = 1; ii < poly.PointCount(); ++ii )
755  LineTo( wxPoint( poly.Point( ii ).x, poly.Point( ii ).y ) );
756 
757  FinishTo(wxPoint( poly.Point( 0 ).x, poly.Point( 0 ).y ) );
758  }
759 }
760 
761 
765 void DXF_PLOTTER::FlashPadTrapez( const wxPoint& aPadPos, const wxPoint *aCorners,
766  double aPadOrient, EDA_DRAW_MODE_T aTrace_Mode, void* aData )
767 {
768  wxASSERT( outputFile );
769  wxPoint coord[4]; /* coord actual corners of a trapezoidal trace */
770 
771  for( int ii = 0; ii < 4; ii++ )
772  {
773  coord[ii] = aCorners[ii];
774  RotatePoint( &coord[ii], aPadOrient );
775  coord[ii] += aPadPos;
776  }
777 
778  // Plot edge:
779  MoveTo( coord[0] );
780  LineTo( coord[1] );
781  LineTo( coord[2] );
782  LineTo( coord[3] );
783  FinishTo( coord[0] );
784 }
785 
794 bool containsNonAsciiChars( const wxString& string )
795 {
796  for( unsigned i = 0; i < string.length(); i++ )
797  {
798  wchar_t ch = string[i];
799  if( ch > 255 )
800  return true;
801  }
802  return false;
803 }
804 
805 void DXF_PLOTTER::Text( const wxPoint& aPos,
806  COLOR4D aColor,
807  const wxString& aText,
808  double aOrient,
809  const wxSize& aSize,
810  enum EDA_TEXT_HJUSTIFY_T aH_justify,
811  enum EDA_TEXT_VJUSTIFY_T aV_justify,
812  int aWidth,
813  bool aItalic,
814  bool aBold,
815  bool aMultilineAllowed,
816  void* aData )
817 {
818  // Fix me: see how to use DXF text mode for multiline texts
819  if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
820  aMultilineAllowed = false; // the text has only one line.
821 
822  if( textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed )
823  {
824  // output text as graphics.
825  // Perhaps multiline texts could be handled as DXF text entity
826  // but I do not want spend time about this (JPC)
827  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
828  aWidth, aItalic, aBold, aMultilineAllowed );
829  }
830  else
831  {
832  /* Emit text as a text entity. This loses formatting and shape but it's
833  more useful as a CAD object */
834  DPOINT origin_dev = userToDeviceCoordinates( aPos );
835  SetColor( aColor );
836  wxString cname = getDXFColorName( m_currentColor );
837  DPOINT size_dev = userToDeviceSize( aSize );
838  int h_code = 0, v_code = 0;
839  switch( aH_justify )
840  {
842  h_code = 0;
843  break;
845  h_code = 1;
846  break;
848  h_code = 2;
849  break;
850  }
851  switch( aV_justify )
852  {
854  v_code = 3;
855  break;
857  v_code = 2;
858  break;
860  v_code = 1;
861  break;
862  }
863 
864  // Position, size, rotation and alignment
865  // The two alignment point usages is somewhat idiot (see the DXF ref)
866  // Anyway since we don't use the fit/aligned options, they're the same
867  fprintf( outputFile,
868  " 0\n"
869  "TEXT\n"
870  " 7\n"
871  "%s\n" // Text style
872  " 8\n"
873  "%s\n" // Layer name
874  " 10\n"
875  "%g\n" // First point X
876  " 11\n"
877  "%g\n" // Second point X
878  " 20\n"
879  "%g\n" // First point Y
880  " 21\n"
881  "%g\n" // Second point Y
882  " 40\n"
883  "%g\n" // Text height
884  " 41\n"
885  "%g\n" // Width factor
886  " 50\n"
887  "%g\n" // Rotation
888  " 51\n"
889  "%g\n" // Oblique angle
890  " 71\n"
891  "%d\n" // Mirror flags
892  " 72\n"
893  "%d\n" // H alignment
894  " 73\n"
895  "%d\n", // V alignment
896  aBold ? (aItalic ? "KICADBI" : "KICADB")
897  : (aItalic ? "KICADI" : "KICAD"),
898  TO_UTF8( cname ),
899  origin_dev.x, origin_dev.x,
900  origin_dev.y, origin_dev.y,
901  size_dev.y, fabs( size_dev.x / size_dev.y ),
902  aOrient / 10.0,
903  aItalic ? DXF_OBLIQUE_ANGLE : 0,
904  size_dev.x < 0 ? 2 : 0, // X mirror flag
905  h_code, v_code );
906 
907  /* There are two issue in emitting the text:
908  - Our overline character (~) must be converted to the appropriate
909  control sequence %%O or %%o
910  - Text encoding in DXF is more or less unspecified since depends on
911  the DXF declared version, the acad version reading it *and* some
912  system variables to be put in the header handled only by newer acads
913  Also before R15 unicode simply is not supported (you need to use
914  bigfonts which are a massive PITA). Common denominator solution:
915  use Latin1 (and however someone could choke on it, anyway). Sorry
916  for the extended latin people. If somewant want to try fixing this
917  recent version seems to use UTF-8 (and not UCS2 like the rest of
918  Windows)
919 
920  XXX Actually there is a *third* issue: older DXF formats are limited
921  to 255 bytes records (it was later raised to 2048); since I'm lazy
922  and text so long is not probable I just don't implement this rule.
923  If someone is interested in fixing this, you have to emit the first
924  partial lines with group code 3 (max 250 bytes each) and then finish
925  with a group code 1 (less than 250 bytes). The DXF refs explains it
926  in no more details...
927  */
928 
929  bool overlining = false;
930  fputs( " 1\n", outputFile );
931  for( unsigned i = 0; i < aText.length(); i++ )
932  {
933  /* Here I do a bad thing: writing the output one byte at a time!
934  but today I'm lazy and I have no idea on how to coerce a Unicode
935  wxString to spit out latin1 encoded text ...
936 
937  Atleast stdio is *supposed* to do output buffering, so there is
938  hope is not too slow */
939  wchar_t ch = aText[i];
940  if( ch > 255 )
941  {
942  // I can't encode this...
943  putc( '?', outputFile );
944  }
945  else
946  {
947  if( ch == '~' )
948  {
949  // Handle the overline toggle
950  fputs( overlining ? "%%o" : "%%O", outputFile );
951  overlining = !overlining;
952  }
953  else
954  {
955  putc( ch, outputFile );
956  }
957  }
958  }
959  putc( '\n', outputFile );
960  }
961 }
962 
void TransformRoundedEndsSegmentToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aStart, wxPoint aEnd, int aCircleToSegmentsCount, int aWidth)
Function TransformRoundedEndsSegmentToPolygon convert a segment with rounded ends to a polygon Conver...
void FinishTo(const wxPoint &pos)
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL) override
DXF polygon: doesn't fill it but at least it close the filled ones DXF does not know thick outline...
static const struct @35 dxf_layer[NBCOLORS]
static const char * getDXFLineType(PlotDashType aType)
EDA_COLOR_T
NOTE: EDA_COLOR_T is deprecated and is kept around for compatibility with legacy canvas.
Definition: colors.h:42
EDA_COLOR_T ColorFindNearest(const wxColour &aColor)
Find the nearest color match.
Definition: colors.cpp:96
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:47
void PenFinish()
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, void *aData=NULL) override
Draws text with the plotter.
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset union For aFastMode meaning, see function booleanOp
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the scale/position for the DXF plot The DXF engine doesn't support line widths and mirroring...
int PointCount() const
Function PointCount()
virtual void FlashPadTrapez(const wxPoint &aPadPos, const wxPoint *aCorners, double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
DXF trapezoidal pad: only sketch mode is supported.
void TransformRoundRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, int aCircleToSegmentsCount)
Function TransformRoundRectToPolygon convert a rectangle with rounded corners to a polygon Convert ar...
virtual void FlashPadCustom(const wxPoint &aPadPos, const wxSize &aSize, SHAPE_POLY_SET *aPolygons, EDA_DRAW_MODE_T aTraceMode, void *aData) override
virtual function FlashPadCustom
virtual void PenTo(const wxPoint &pos, char plume) override
moveto/lineto primitive, moves the 'pen' to the specified direction
double g
Green component.
Definition: color4d.h:292
static const double DXF_OBLIQUE_ANGLE
Oblique angle for DXF native text (I don't remember if 15 degrees is the ISO value...
bool colorMode
static wxString getDXFColorName(COLOR4D aColor)
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
COLOR4D m_currentColor
int OutlineCount() const
Returns the number of outlines in the set
double m_IUsPerDecimil
PlotDashType
Enum for choosing dashed line type.
Definition: class_plotter.h:83
wxPoint plotOffset
Plot offset (in IUs)
wxPoint penLastpos
Last pen positions; set to -1,-1 when the pen is at rest.
double b
Blue component.
Definition: color4d.h:293
This file contains miscellaneous commonly used macros and functions.
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, void *aData=NULL)
Draws text with the plotter.
Definition: drawtxt.cpp:229
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
virtual void ThickSegment(const wxPoint &start, const wxPoint &end, int width, EDA_DRAW_MODE_T tracemode, void *aData) override
void LineTo(const wxPoint &pos)
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
virtual bool StartPlot() override
Opens the DXF plot with a skeleton header.
bool containsNonAsciiChars(const wxString &string)
Checks if a given string contains non-ASCII characters.
T AddAngles(T a1, T2 a2)
Add two angles (keeping the result normalized). T2 is here.
Definition: trigo.h:267
Class SHAPE_POLY_SET.
Base window classes and related definitions.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
EDA_DRAW_MODE_T
Definition: eda_text.h:62
double plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
virtual bool EndPlot() override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
DXF rectangle: fill not supported.
virtual void FlashPadCircle(const wxPoint &pos, int diametre, EDA_DRAW_MODE_T trace_mode, void *aData) override
DXF round pad: always done in sketch mode; it could be filled but it isn't pretty if other kinds of p...
virtual DPOINT userToDeviceSize(const wxSize &size)
Modifies size according to the plotter scale factors (wxSize version, returns a DPOINT) ...
int NewOutline()
Creates a new empty polygon in the set and returns its index
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
virtual void Circle(const wxPoint &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
DXF circle: full functionality; it even does 'fills' drawing a circle with a dual-arc polyline wide a...
virtual void FlashPadRect(const wxPoint &pos, const wxSize &size, double orient, EDA_DRAW_MODE_T trace_mode, void *aData) override
DXF rectangular pad: alwayd done in sketch mode.
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:54
void MoveTo(const wxPoint &pos)
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
Class SHAPE_LINE_CHAIN.
virtual void SetDefaultLineWidth(int width) override
Set the default line width.
FILE * outputFile
true if the Y axis is top to bottom (SVG)
virtual void SetColor(COLOR4D color) override
The DXF exporter handles 'colors' as layers...
virtual void SetDash(int dashed) override
Definition: colors.h:49
virtual void FlashPadOval(const wxPoint &pos, const wxSize &size, double orient, EDA_DRAW_MODE_T trace_mode, void *aData) override
DXF oval pad: always done in sketch mode.
const char * name
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:70
VECTOR2I & Point(int aIndex)
Function Point()
Definition: colors.h:45
double r
Red component.
Definition: color4d.h:291
Basic classes for most KiCad items.
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.
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
Number of colors.
Definition: colors.h:75
void sketchOval(const wxPoint &pos, const wxSize &size, double orient, int width)
virtual void FlashPadRoundRect(const wxPoint &aPadPos, const wxSize &aSize, int aCornerRadius, double aOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
virtual function FlashPadRoundRect
wxSize paperSize
Paper size in IU - not in mils.
EDA_COLOR_T NextColor(EDA_COLOR_T &aColor)
Definition: colors.h:87
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline) ...
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39