KiCad PCB EDA Suite
SVG_plotter.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 2020 Jean-Pierre Charras, jp.charras at wanadoo.fr
10  * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 /* Some info on basic items SVG format, used here:
31  * The root element of all SVG files is the <svg> element.
32  *
33  * The <g> element is used to group SVG shapes together.
34  * Once grouped you can transform the whole group of shapes as if it was a single shape.
35  * This is an advantage compared to a nested <svg> element
36  * which cannot be the target of transformation by itself.
37  *
38  * The <rect> element represents a rectangle.
39  * Using this element you can draw rectangles of various width, height,
40  * with different stroke (outline) and fill colors, with sharp or rounded corners etc.
41  *
42  * <svg xmlns="http://www.w3.org/2000/svg"
43  * xmlns:xlink="http://www.w3.org/1999/xlink">
44  *
45  * <rect x="10" y="10" height="100" width="100"
46  * style="stroke:#006600; fill: #00cc00"/>
47  *
48  * </svg>
49  *
50  * The <circle> element is used to draw circles.
51  * <circle cx="40" cy="40" r="24" style="stroke:#006600; fill:#00cc00"/>
52  *
53  * The <ellipse> element is used to draw ellipses.
54  * An ellipse is a circle that does not have equal height and width.
55  * Its radius in the x and y directions are different, in other words.
56  * <ellipse cx="40" cy="40" rx="30" ry="15"
57  * style="stroke:#006600; fill:#00cc00"/>
58  *
59  * The <line> element is used to draw lines.
60  *
61  * <line x1="0" y1="10" x2="0" y2="100" style="stroke:#006600;"/>
62  * <line x1="10" y1="10" x2="100" y2="100" style="stroke:#006600;"/>
63  *
64  * The <polyline> element is used to draw multiple connected lines
65  * Here is a simple example:
66  *
67  * <polyline points="0,0 30,0 15,30" style="stroke:#006600;"/>
68  *
69  * The <polygon> element is used to draw with multiple (3 or more) sides / edges.
70  * Here is a simple example:
71  *
72  * <polygon points="0,0 50,0 25,50" style="stroke:#660000; fill:#cc3333;"/>
73  *
74  * The <path> element is used to draw advanced shapes combined from lines and arcs,
75  * with or without fill.
76  * It is probably the most advanced and versatile SVG shape of them all.
77  * It is probably also the hardest element to master.
78  * <path d="M50,50
79  * A30,30 0 0,1 35,20
80  * L100,100
81  * M110,110
82  * L100,0"
83  * style="stroke:#660000; fill:none;"/>
84  *
85  * Draw an elliptic arc: it is one of basic path command:
86  * <path d="M(startx,starty) A(radiusx,radiusy)
87  * rotation-axe-x
88  * flag_arc_large,flag_sweep endx,endy">
89  * flag_arc_large: 0 = small arc > 180 deg, 1 = large arc > 180 deg
90  * flag_sweep : 0 = CCW, 1 = CW
91  * The center of ellipse is automatically calculated.
92  */
93 
94 #include <base64.h>
95 #include <fctsys.h>
96 #include <trigo.h>
97 #include <eda_base_frame.h>
98 #include <eda_rect.h>
99 #include <base_struct.h>
100 #include <common.h>
101 #include <plotter.h>
102 #include <macros.h>
103 #include <kicad_string.h>
104 
105 #include <cstdint>
106 #include <wx/mstream.h>
107 
114 static wxString XmlEsc( const wxString& aStr, bool isAttribute = false )
115 {
116  wxString escaped;
117 
118  escaped.reserve( aStr.length() );
119 
120  for( wxString::const_iterator it = aStr.begin(); it != aStr.end(); ++it )
121  {
122  const wxChar c = *it;
123 
124  switch( c )
125  {
126  case wxS( '<' ):
127  escaped.append( wxS( "&lt;" ) );
128  break;
129  case wxS( '>' ):
130  escaped.append( wxS( "&gt;" ) );
131  break;
132  case wxS( '&' ):
133  escaped.append( wxS( "&amp;" ) );
134  break;
135  case wxS( '\r' ):
136  escaped.append( wxS( "&#xD;" ) );
137  break;
138  default:
139  if( isAttribute )
140  {
141  switch( c )
142  {
143  case wxS( '"' ):
144  escaped.append( wxS( "&quot;" ) );
145  break;
146  case wxS( '\t' ):
147  escaped.append( wxS( "&#x9;" ) );
148  break;
149  case wxS( '\n' ):
150  escaped.append( wxS( "&#xA;" ));
151  break;
152  default:
153  escaped.append(c);
154  }
155  }
156  else
157  escaped.append(c);
158  }
159  }
160 
161  return escaped;
162 }
163 
164 
166 {
167  m_graphics_changed = true;
169  m_fillMode = NO_FILL; // or FILLED_SHAPE or FILLED_WITH_BG_BODYCOLOR
170  m_pen_rgb_color = 0; // current color value (black)
171  m_brush_rgb_color = 0; // current color value (black)
173  m_useInch = true; // decimils is the default
174  m_precision = 4; // because there where used before it was changable
175 }
176 
177 
178 void SVG_PLOTTER::SetViewport( const wxPoint& aOffset, double aIusPerDecimil,
179  double aScale, bool aMirror )
180 {
181  m_plotMirror = aMirror;
182  m_yaxisReversed = true; // unlike other plotters, SVG has Y axis reversed
183  plotOffset = aOffset;
184  plotScale = aScale;
185  m_IUsPerDecimil = aIusPerDecimil;
186 
187  /* Compute the paper size in IUs */
189  paperSize.x *= 10.0 * aIusPerDecimil;
190  paperSize.y *= 10.0 * aIusPerDecimil;
191 
192  // set iuPerDeviceUnit, in 0.1mils ( 2.54um )
193  // this was used before the format was changable, so we set is as default
194  SetSvgCoordinatesFormat( 4, true );
195 }
196 
197 void SVG_PLOTTER::SetSvgCoordinatesFormat( unsigned aResolution, bool aUseInches )
198 {
199  m_useInch = aUseInches;
200  m_precision = aResolution;
201 
202  // gives now a default value to iuPerDeviceUnit (because the units of the caller is now known)
203  double iusPerMM = m_IUsPerDecimil / 2.54 * 1000;
204  iuPerDeviceUnit = pow( 10.0, m_precision ) / ( iusPerMM );
205 
206  if( m_useInch )
207  iuPerDeviceUnit /= 25.4; // convert to inch
208 }
209 
210 
212 {
214 
215  if( m_graphics_changed )
216  setSVGPlotStyle();
217 }
218 
219 
221 {
222  if( m_fillMode != fill )
223  {
224  m_graphics_changed = true;
225  m_fillMode = fill;
226  }
227 }
228 
229 
230 void SVG_PLOTTER::setSVGPlotStyle( bool aIsGroup, const std::string& aExtraStyle )
231 {
232  if( aIsGroup )
233  fputs( "</g>\n<g ", outputFile );
234 
235  // output the background fill color
236  fprintf( outputFile, "style=\"fill:#%6.6lX; ", m_brush_rgb_color );
237 
238  switch( m_fillMode )
239  {
240  case NO_FILL:
241  fputs( "fill-opacity:0.0; ", outputFile );
242  break;
243 
244  case FILLED_SHAPE:
245  fputs( "fill-opacity:1.0; ", outputFile );
246  break;
247 
249  fputs( "fill-opacity:0.6; ", outputFile );
250  break;
251 
252  case FILLED_WITH_COLOR:
253  wxFAIL_MSG( "FILLED_WITH_COLOR not implemented" );
254  break;
255  }
256 
257  double pen_w = userToDeviceSize( GetCurrentLineWidth() );
258 
259  if( pen_w < 0.0 ) // Ensure pen width validity
260  pen_w = 0.0;
261 
262  fprintf( outputFile, "\nstroke:#%6.6lX; stroke-width:%f; stroke-opacity:1; \n",
263  m_pen_rgb_color, pen_w );
264  fputs( "stroke-linecap:round; stroke-linejoin:round;", outputFile );
265 
266  //set any extra attributes for non-solid lines
267  switch( m_dashed )
268  {
270  fprintf( outputFile, "stroke-dasharray:%f,%f;", GetDashMarkLenIU(), GetDashGapLenIU() );
271  break;
272  case PLOT_DASH_TYPE::DOT:
273  fprintf( outputFile, "stroke-dasharray:%f,%f;", GetDotMarkLenIU(), GetDashGapLenIU() );
274  break;
276  fprintf( outputFile, "stroke-dasharray:%f,%f,%f,%f;", GetDashMarkLenIU(), GetDashGapLenIU(),
278  break;
281  default:
282  //do nothing
283  break;
284  }
285 
286  if( aExtraStyle.length() )
287  {
288  fputs( aExtraStyle.c_str(), outputFile );
289  }
290 
291  fputs( "\"", outputFile );
292 
293  if( aIsGroup )
294  {
295  fputs( ">", outputFile );
296  m_graphics_changed = false;
297  }
298 
299  fputs( "\n", outputFile );
300 }
301 
302 /* Set the current line width (in IUs) for the next plot
303  */
304 void SVG_PLOTTER::SetCurrentLineWidth( int aWidth, void* aData )
305 {
306  if( aWidth == DO_NOT_SET_LINE_WIDTH )
307  return;
308  else if( aWidth == USE_DEFAULT_LINE_WIDTH )
310  else if( aWidth == 0 )
311  aWidth = 1;
312 
313  wxASSERT_MSG( aWidth > 0, "Plotter called to set negative pen width" );
314 
315  if( aWidth != currentPenWidth )
316  {
317  m_graphics_changed = true;
318  currentPenWidth = aWidth;
319  }
320 
321  if( m_graphics_changed )
322  setSVGPlotStyle();
323 }
324 
325 
326 void SVG_PLOTTER::StartBlock( void* aData )
327 {
328  std::string* idstr = reinterpret_cast<std::string*>( aData );
329 
330  fputs( "<g ", outputFile );
331  if( idstr )
332  fprintf( outputFile, "id=\"%s\"", idstr->c_str() );
333 
334  fprintf( outputFile, ">\n" );
335 }
336 
337 
338 void SVG_PLOTTER::EndBlock( void* aData )
339 {
340  fprintf( outputFile, "</g>\n" );
341 
342  m_graphics_changed = true;
343 }
344 
345 
346 /* initialize m_red, m_green, m_blue ( 0 ... 255)
347  * from reduced values r, g ,b ( 0.0 to 1.0 )
348  */
349 void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b )
350 {
351  int red = (int) ( 255.0 * r );
352  int green = (int) ( 255.0 * g );
353  int blue = (int) ( 255.0 * b );
354  long rgb_color = (red << 16) | (green << 8) | blue;
355 
356  if( m_pen_rgb_color != rgb_color )
357  {
358  m_graphics_changed = true;
359  m_pen_rgb_color = rgb_color;
360 
361  // Currently, use the same color for brush and pen
362  // (i.e. to draw and fill a contour)
363  m_brush_rgb_color = rgb_color;
364  }
365 }
366 
367 
372 {
373  if( m_dashed != dashed )
374  {
375  m_graphics_changed = true;
376  m_dashed = dashed;
377  }
378 
379  if( m_graphics_changed )
380  setSVGPlotStyle();
381 }
382 
383 
384 void SVG_PLOTTER::Rect( const wxPoint& p1, const wxPoint& p2, FILL_T fill, int width )
385 {
386  EDA_RECT rect( p1, wxSize( p2.x -p1.x, p2.y -p1.y ) );
387  rect.Normalize();
388  DPOINT org_dev = userToDeviceCoordinates( rect.GetOrigin() );
389  DPOINT end_dev = userToDeviceCoordinates( rect.GetEnd() );
390  DSIZE size_dev = end_dev - org_dev;
391  // Ensure size of rect in device coordinates is > 0
392  // I don't know if this is a SVG issue or a Inkscape issue, but
393  // Inkscape has problems with negative or null values for width and/or height, so avoid them
394  DBOX rect_dev( org_dev, size_dev);
395  rect_dev.Normalize();
396 
397  setFillMode( fill );
398  SetCurrentLineWidth( width );
399 
400  // Rectangles having a 0 size value for height or width are just not drawn on Inscape,
401  // so use a line when happens.
402  if( rect_dev.GetSize().x == 0.0 || rect_dev.GetSize().y == 0.0 ) // Draw a line
403  fprintf( outputFile,
404  "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" />\n",
405  rect_dev.GetPosition().x, rect_dev.GetPosition().y,
406  rect_dev.GetEnd().x, rect_dev.GetEnd().y
407  );
408 
409  else
410  fprintf( outputFile,
411  "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" rx=\"%f\" />\n",
412  rect_dev.GetPosition().x, rect_dev.GetPosition().y,
413  rect_dev.GetSize().x, rect_dev.GetSize().y,
414  0.0 // radius of rounded corners
415  );
416 }
417 
418 
419 void SVG_PLOTTER::Circle( const wxPoint& pos, int diametre, FILL_T fill, int width )
420 {
421  DPOINT pos_dev = userToDeviceCoordinates( pos );
422  double radius = userToDeviceSize( diametre / 2.0 );
423 
424  setFillMode( fill );
425  SetCurrentLineWidth( width );
426 
427  // If diameter is less than width, switch to filled mode
428  if( fill == NO_FILL && diametre < width )
429  {
431  SetCurrentLineWidth( 0 );
432 
433  radius = userToDeviceSize( ( diametre / 2.0 ) + ( width / 2.0 ) );
434  }
435 
436  fprintf( outputFile,
437  "<circle cx=\"%f\" cy=\"%f\" r=\"%f\" /> \n",
438  pos_dev.x, pos_dev.y, radius );
439 }
440 
441 
442 void SVG_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
443  FILL_T fill, int width )
444 {
445  /* Draws an arc of a circle, centred on (xc,yc), with starting point
446  * (x1, y1) and ending at (x2, y2). The current pen is used for the outline
447  * and the current brush for filling the shape.
448  *
449  * The arc is drawn in an anticlockwise direction from the start point to
450  * the end point
451  */
452 
453  if( radius <= 0 )
454  {
455  Circle( centre, width, FILLED_SHAPE, 0 );
456  return;
457  }
458 
459  if( StAngle > EndAngle )
460  std::swap( StAngle, EndAngle );
461 
462  // Calculate start point.
463  DPOINT centre_dev = userToDeviceCoordinates( centre );
464  double radius_dev = userToDeviceSize( radius );
465 
466  if( !m_yaxisReversed ) // Should be never the case
467  {
468  double tmp = StAngle;
469  StAngle = -EndAngle;
470  EndAngle = -tmp;
471  }
472 
473  if( m_plotMirror )
474  {
476  {
477  StAngle = 1800.0 -StAngle;
478  EndAngle = 1800.0 -EndAngle;
479  std::swap( StAngle, EndAngle );
480  }
481  else
482  {
483  StAngle = -StAngle;
484  EndAngle = -EndAngle;
485  }
486  }
487 
488  DPOINT start;
489  start.x = radius_dev;
490  RotatePoint( &start.x, &start.y, StAngle );
491  DPOINT end;
492  end.x = radius_dev;
493  RotatePoint( &end.x, &end.y, EndAngle );
494  start += centre_dev;
495  end += centre_dev;
496 
497  double theta1 = DECIDEG2RAD( StAngle );
498 
499  if( theta1 < 0 )
500  theta1 = theta1 + M_PI * 2;
501 
502  double theta2 = DECIDEG2RAD( EndAngle );
503 
504  if( theta2 < 0 )
505  theta2 = theta2 + M_PI * 2;
506 
507  if( theta2 < theta1 )
508  theta2 = theta2 + M_PI * 2;
509 
510  int flg_arc = 0; // flag for large or small arc. 0 means less than 180 degrees
511 
512  if( fabs( theta2 - theta1 ) > M_PI )
513  flg_arc = 1;
514 
515  int flg_sweep = 0; // flag for sweep always 0
516 
517  // Draw a single arc: an arc is one of 3 curve commands (2 other are 2 bezier curves)
518  // params are start point, radius1, radius2, X axe rotation,
519  // flag arc size (0 = small arc > 180 deg, 1 = large arc > 180 deg),
520  // sweep arc ( 0 = CCW, 1 = CW),
521  // end point
522  if( fill != NO_FILL )
523  {
524  // Filled arcs (in eeschema) consist of the pie wedge and a stroke only on the arc
525  // This needs to be drawn in two steps.
526  setFillMode( fill );
527  SetCurrentLineWidth( 0 );
528 
529  fprintf( outputFile, "<path d=\"M%f %f A%f %f 0.0 %d %d %f %f L %f %f Z\" />\n",
530  start.x, start.y, radius_dev, radius_dev,
531  flg_arc, flg_sweep,
532  end.x, end.y, centre_dev.x, centre_dev.y );
533  }
534 
535  setFillMode( NO_FILL );
536  SetCurrentLineWidth( width );
537  fprintf( outputFile, "<path d=\"M%f %f A%f %f 0.0 %d %d %f %f\" />\n",
538  start.x, start.y, radius_dev, radius_dev,
539  flg_arc, flg_sweep,
540  end.x, end.y );
541 }
542 
543 
544 void SVG_PLOTTER::BezierCurve( const wxPoint& aStart, const wxPoint& aControl1,
545  const wxPoint& aControl2, const wxPoint& aEnd,
546  int aTolerance, int aLineThickness )
547 {
548 #if 1
549  setFillMode( NO_FILL );
550  SetCurrentLineWidth( aLineThickness );
551 
552  DPOINT start = userToDeviceCoordinates( aStart );
553  DPOINT ctrl1 = userToDeviceCoordinates( aControl1 );
554  DPOINT ctrl2 = userToDeviceCoordinates( aControl2 );
555  DPOINT end = userToDeviceCoordinates( aEnd );
556 
557  // Generate a cubic curve: start point and 3 other control points.
558  fprintf( outputFile, "<path d=\"M%f,%f C%f,%f %f,%f %f,%f\" />\n",
559  start.x, start.y, ctrl1.x, ctrl1.y,
560  ctrl2.x, ctrl2.y, end.x, end.y );
561 #else
562  PLOTTER::BezierCurve( aStart, aControl1,aControl2, aEnd,aTolerance, aLineThickness );
563 #endif
564 }
565 
566 
567 void SVG_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
568  FILL_T aFill, int aWidth, void * aData )
569 {
570  if( aCornerList.size() <= 1 )
571  return;
572 
573  setFillMode( aFill );
574  SetCurrentLineWidth( aWidth );
575  fprintf( outputFile, "<path ");
576 
577  switch( aFill )
578  {
579  case NO_FILL:
580  setSVGPlotStyle( false, "fill:none" );
581  break;
582 
584  case FILLED_SHAPE:
585  setSVGPlotStyle( false, "fill-rule:evenodd;" );
586  break;
587 
588  case FILLED_WITH_COLOR:
589  wxFAIL_MSG( "FILLED_WITH_COLOR not implemented" );
590  break;
591  }
592 
593  DPOINT pos = userToDeviceCoordinates( aCornerList[0] );
594  fprintf( outputFile, "d=\"M %f,%f\n", pos.x, pos.y );
595 
596  for( unsigned ii = 1; ii < aCornerList.size() - 1; ii++ )
597  {
598  pos = userToDeviceCoordinates( aCornerList[ii] );
599  fprintf( outputFile, "%f,%f\n", pos.x, pos.y );
600  }
601 
602  // If the cornerlist ends where it begins, then close the poly
603  if( aCornerList.front() == aCornerList.back() )
604  fprintf( outputFile, "Z\" /> \n" );
605  else
606  {
607  pos = userToDeviceCoordinates( aCornerList.back() );
608  fprintf( outputFile, "%f,%f\n\" /> \n", pos.x, pos.y );
609  }
610 }
611 
612 
616 void SVG_PLOTTER::PlotImage( const wxImage& aImage, const wxPoint& aPos,
617  double aScaleFactor )
618 {
619  wxSize pix_size( aImage.GetWidth(), aImage.GetHeight() );
620 
621  // Requested size (in IUs)
622  DPOINT drawsize( aScaleFactor * pix_size.x,
623  aScaleFactor * pix_size.y );
624 
625  // calculate the bitmap start position
626  wxPoint start( aPos.x - drawsize.x / 2,
627  aPos.y - drawsize.y / 2);
628 
629  // Rectangles having a 0 size value for height or width are just not drawn on Inscape,
630  // so use a line when happens.
631  if( drawsize.x == 0.0 || drawsize.y == 0.0 ) // Draw a line
632  {
633  PLOTTER::PlotImage( aImage, aPos, aScaleFactor );
634  }
635  else
636  {
637  wxMemoryOutputStream img_stream;
638 
639  aImage.SaveFile( img_stream, wxBITMAP_TYPE_PNG );
640  size_t input_len = img_stream.GetOutputStreamBuffer()->GetBufferSize();
641  std::vector<uint8_t> buffer( input_len );
642  std::vector<uint8_t> encoded;
643 
644  img_stream.CopyTo( buffer.data(), buffer.size() );
645  base64::encode( buffer, encoded );
646 
647  fprintf( outputFile,
648  "<image x=\"%f\" y=\"%f\" xlink:href=\"data:image/png;base64,",
649  userToDeviceSize( start.x ), userToDeviceSize( start.y )
650  );
651 
652  for( size_t i = 0; i < encoded.size(); i++ )
653  {
654  fprintf( outputFile, "%c", static_cast<char>( encoded[i] ) );
655 
656  if( ( i % 64 ) == 63 )
657  fprintf( outputFile, "\n" );
658  }
659 
660  fprintf( outputFile, "\"\npreserveAspectRatio=\"none\" width=\"%f\" height=\"%f\" />",
661  userToDeviceSize( drawsize.x ), userToDeviceSize( drawsize.y ) );
662  }
663 }
664 
665 
666 void SVG_PLOTTER::PenTo( const wxPoint& pos, char plume )
667 {
668  if( plume == 'Z' )
669  {
670  if( penState != 'Z' )
671  {
672  fputs( "\" />\n", outputFile );
673  penState = 'Z';
674  penLastpos.x = -1;
675  penLastpos.y = -1;
676  }
677 
678  return;
679  }
680 
681  if( penState == 'Z' ) // here plume = 'D' or 'U'
682  {
683  DPOINT pos_dev = userToDeviceCoordinates( pos );
684 
685  // Ensure we do not use a fill mode when moving tne pen,
686  // in SVG mode (i;e. we are plotting only basic lines, not a filled area
687  if( m_fillMode != NO_FILL )
688  {
689  setFillMode( NO_FILL );
690  setSVGPlotStyle();
691  }
692 
693  fprintf( outputFile, "<path d=\"M%d %d\n",
694  (int) pos_dev.x, (int) pos_dev.y );
695  }
696  else if( penState != plume || pos != penLastpos )
697  {
698  DPOINT pos_dev = userToDeviceCoordinates( pos );
699  fprintf( outputFile, "L%d %d\n",
700  (int) pos_dev.x, (int) pos_dev.y );
701  }
702 
703  penState = plume;
704  penLastpos = pos;
705 }
706 
707 
713 {
714  wxASSERT( outputFile );
715  wxString msg;
716 
717  static const char* header[] =
718  {
719  "<?xml version=\"1.0\" standalone=\"no\"?>\n",
720  " <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \n",
721  " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> \n",
722  "<svg\n"
723  " xmlns:svg=\"http://www.w3.org/2000/svg\"\n"
724  " xmlns=\"http://www.w3.org/2000/svg\"\n",
725  " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n",
726  " version=\"1.1\"\n",
727  NULL
728  };
729 
730  // Write header.
731  for( int ii = 0; header[ii] != NULL; ii++ )
732  {
733  fputs( header[ii], outputFile );
734  }
735 
736  // Write viewport pos and size
737  wxPoint origin; // TODO set to actual value
738  fprintf( outputFile, " width=\"%fcm\" height=\"%fcm\" viewBox=\"%d %d %d %d\">\n",
739  (double) paperSize.x / m_IUsPerDecimil * 2.54 / 10000,
740  (double) paperSize.y / m_IUsPerDecimil * 2.54 / 10000, origin.x, origin.y,
741  (int) ( paperSize.x * iuPerDeviceUnit ), (int) ( paperSize.y * iuPerDeviceUnit) );
742 
743  // Write title
744  char date_buf[250];
745  time_t ltime = time( NULL );
746  strftime( date_buf, 250, "%Y/%m/%d %H:%M:%S",
747  localtime( &ltime ) );
748 
749  fprintf( outputFile,
750  "<title>SVG Picture created as %s date %s </title>\n",
751  TO_UTF8( XmlEsc( wxFileName( filename ).GetFullName() ) ), date_buf );
752  // End of header
753  fprintf( outputFile, " <desc>Picture generated by %s </desc>\n",
754  TO_UTF8( XmlEsc( creator ) ) );
755 
756  // output the pen and brush color (RVB values in hex) and opacity
757  double opacity = 1.0; // 0.0 (transparent to 1.0 (solid)
758  fprintf( outputFile,
759  "<g style=\"fill:#%6.6lX; fill-opacity:%f;stroke:#%6.6lX; stroke-opacity:%f;\n",
760  m_brush_rgb_color, opacity, m_pen_rgb_color, opacity );
761 
762  // output the pen cap and line joint
763  fputs( "stroke-linecap:round; stroke-linejoin:round;\"\n", outputFile );
764  fputs( " transform=\"translate(0 0) scale(1 1)\">\n", outputFile );
765  return true;
766 }
767 
768 
770 {
771  fputs( "</g> \n</svg>\n", outputFile );
772  fclose( outputFile );
773  outputFile = NULL;
774 
775  return true;
776 }
777 
778 
779 void SVG_PLOTTER::Text( const wxPoint& aPos,
780  const COLOR4D aColor,
781  const wxString& aText,
782  double aOrient,
783  const wxSize& aSize,
784  enum EDA_TEXT_HJUSTIFY_T aH_justify,
785  enum EDA_TEXT_VJUSTIFY_T aV_justify,
786  int aWidth,
787  bool aItalic,
788  bool aBold,
789  bool aMultilineAllowed,
790  void* aData )
791 {
792  setFillMode( NO_FILL );
793  SetColor( aColor );
794  SetCurrentLineWidth( aWidth );
795 
796  wxPoint text_pos = aPos;
797  const char *hjust = "start";
798 
799  switch( aH_justify )
800  {
802  hjust = "middle";
803  break;
804 
806  hjust = "end";
807  break;
808 
810  hjust = "start";
811  break;
812  }
813 
814  switch( aV_justify )
815  {
817  text_pos.y += aSize.y / 2;
818  break;
819 
821  text_pos.y += aSize.y;
822  break;
823 
825  break;
826  }
827 
828  wxSize text_size;
829  // aSize.x or aSize.y is < 0 for mirrored texts.
830  // The actual text size value is the absolue value
831  text_size.x = std::abs( GraphicTextWidth( aText, aSize, aItalic, aWidth ) );
832  text_size.y = std::abs( aSize.x * 4/3 ); // Hershey font height to em size conversion
833  DPOINT anchor_pos_dev = userToDeviceCoordinates( aPos );
834  DPOINT text_pos_dev = userToDeviceCoordinates( text_pos );
835  DPOINT sz_dev = userToDeviceSize( text_size );
836 
837  if( aOrient != 0 ) {
838  fprintf( outputFile,
839  "<g transform=\"rotate(%f %f %f)\">\n",
840  - aOrient * 0.1, anchor_pos_dev.x, anchor_pos_dev.y );
841  }
842 
843  fprintf( outputFile,
844  "<text x=\"%f\" y=\"%f\"\n", text_pos_dev.x, text_pos_dev.y );
845 
847  if( aSize.x < 0 )
848  fprintf( outputFile, "transform=\"scale(-1 1) translate(%f 0)\"\n", -2 * text_pos_dev.x );
849 
850  fprintf( outputFile,
851  "textLength=\"%f\" font-size=\"%f\" lengthAdjust=\"spacingAndGlyphs\"\n"
852  "text-anchor=\"%s\" opacity=\"0\">%s</text>\n",
853  sz_dev.x, sz_dev.y,
854  hjust, TO_UTF8( XmlEsc( aText ) ) );
855 
856  if( aOrient != 0 )
857  fputs( "</g>\n", outputFile );
858 
859  fprintf( outputFile,
860  "<g class=\"stroked-text\"><desc>%s</desc>\n",
861  TO_UTF8( XmlEsc( aText ) ) );
862  PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
863  aWidth, aItalic, aBold, aMultilineAllowed );
864  fputs( "</g>", outputFile );
865 }
double GetDotMarkLenIU() const
Definition: plotter.cpp:140
unsigned m_precision
Definition: plotter.h:1043
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:48
virtual void SetDash(PLOT_DASH_TYPE dashed) override
SVG supports dashed lines.
virtual void PlotImage(const wxImage &aImage, const wxPoint &aPos, double aScaleFactor) override
Postscript-likes at the moment are the only plot engines supporting bitmaps...
virtual void SetSvgCoordinatesFormat(unsigned aResolution, bool aUseInches=false) override
Function SetSvgCoordinatesFormat selection of SVG step size (number of digits needed for 1 mm or 1 in...
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
const Vec GetEnd() const
Definition: box2.h:195
FILL_T m_fillMode
Definition: plotter.h:1028
void setFillMode(FILL_T fill)
function setFillMode() prepare parameters for setSVGPlotStyle()
int color
Definition: DXF_plotter.cpp:61
virtual void PenTo(const wxPoint &pos, char plume) override
moveto/lineto primitive, moves the 'pen' to the specified direction
void setSVGPlotStyle(bool aIsGroup=true, const std::string &aExtraStyle={})
function setSVGPlotStyle() output the string which define pen and brush color, shape,...
virtual void BezierCurve(const wxPoint &aStart, const wxPoint &aControl1, const wxPoint &aControl2, const wxPoint &aEnd, int aTolerance, int aLineThickness=USE_DEFAULT_LINE_WIDTH)
Generic fallback: Cubic Bezier curve rendered as a polyline In Kicad the bezier curves have 4 control...
Definition: plotter.cpp:204
int GraphicTextWidth(const wxString &aText, const wxSize &aSize, bool aItalic, bool aBold)
Function GraphicTextWidth.
Definition: gr_text.cpp:98
char penState
Definition: plotter.h:592
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
double m_IUsPerDecimil
Definition: plotter.h:571
wxPoint plotOffset
Plot offset (in IUs)
Definition: plotter.h:577
wxPoint penLastpos
Definition: plotter.h:593
static wxString XmlEsc(const wxString &aStr, bool isAttribute=false)
Function XmlEsc translates '<' to "<", '>' to ">" and so on, according to the spec: http://www....
PAGE_INFO pageInfo
Definition: plotter.h:598
PLOT_DASH_TYPE m_dashed
Definition: plotter.h:1039
This file contains miscellaneous commonly used macros and functions.
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
virtual void Text(const wxPoint &aPos, const COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, bool aMultilineAllowed=false, void *aData=NULL)
Draws text with the plotter.
Definition: gr_text.cpp:222
void encode(const std::vector< uint8_t > &aInput, std::vector< uint8_t > &aOutput)
Definition: base64.cpp:76
double GetDashGapLenIU() const
Definition: plotter.cpp:152
virtual int GetCurrentLineWidth() const
Definition: plotter.h:158
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.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:100
virtual bool EndPlot() override
bool m_yaxisReversed
true to mirror horizontally (else vertically)
Definition: plotter.h:583
const wxPoint GetEnd() const
Definition: eda_rect.h:116
virtual void SetColor(COLOR4D color) override
The SetColor implementation is split with the subclasses: The PSLIKE computes the rgb values,...
static const int USE_DEFAULT_LINE_WIDTH
Definition: plotter.h:119
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plotter.h:581
#define NULL
virtual void SetTextMode(PLOT_TEXT_MODE mode) override
PS and PDF fully implement native text (for the Latin-1 subset)
Definition: plotter.h:707
long m_pen_rgb_color
Definition: plotter.h:1030
const wxPoint GetOrigin() const
Definition: eda_rect.h:114
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.
BOX2< Vec > & Normalize()
Function Normalize ensures that the height ant width are positive.
Definition: box2.h:129
virtual void SetColor(COLOR4D color) override
The SetColor implementation is split with the subclasses: The PSLIKE computes the rgb values,...
Definition: PS_plotter.cpp:52
bool m_useInch
Definition: plotter.h:1040
Base window classes and related definitions.
double plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plotter.h:565
virtual bool StartPlot() override
The code within this function creates SVG files header.
RENDER_SETTINGS * m_renderSettings
Definition: plotter.h:603
const wxSize & GetSizeMils() const
Definition: page_info.h:143
virtual DPOINT userToDeviceSize(const wxSize &size)
Modifies size according to the plotter scale factors (wxSize version, returns a DPOINT)
Definition: plotter.cpp:125
virtual void SetCurrentLineWidth(int width, void *aData=NULL) override
Set the line width for the next drawing.
virtual void Circle(const wxPoint &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH) override
PLOT_DASH_TYPE
Enum for choosing dashed line type.
Definition: plotter.h:87
EDA_TEXT_VJUSTIFY_T
Definition: eda_text.h:55
const Vec & GetPosition() const
Definition: box2.h:194
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
Definition: plotter.cpp:94
void Normalize()
Function Normalize ensures that the height ant width are positive.
virtual void PlotImage(const wxImage &aImage, const wxPoint &aPos, double aScaleFactor)
Function PlotImage Only Postscript plotters can plot bitmaps for plotters that cannot plot a bitmap,...
Definition: plotter.cpp:232
int currentPenWidth
Definition: plotter.h:591
double GetDashMarkLenIU() const
Definition: plotter.cpp:146
bool m_graphics_changed
Definition: plotter.h:1036
long m_brush_rgb_color
Definition: plotter.h:1034
virtual void EndBlock(void *aData) override
calling this function allows one to define the end of a group of drawing items the group is started b...
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plotter.h:586
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
double DECIDEG2RAD(double deg)
Definition: trigo.h:223
virtual void emitSetRGBColor(double r, double g, double b) override
function emitSetRGBColor() initialize m_pen_rgb_color from reduced values r, g ,b ( reduced values ar...
The common library.
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:42
int GetDefaultPenWidth() const
virtual void StartBlock(void *aData) override
calling this function allows one to define the beginning of a group of drawing items (used in SVG for...
const Vec & GetSize() const
Definition: box2.h:189
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plotter.h:574
static const int DO_NOT_SET_LINE_WIDTH
Definition: plotter.h:118
wxString filename
Definition: plotter.h:596
virtual void BezierCurve(const wxPoint &aStart, const wxPoint &aControl1, const wxPoint &aControl2, const wxPoint &aEnd, int aTolerance, int aLineThickness=USE_DEFAULT_LINE_WIDTH) override
Generic fallback: Cubic Bezier curve rendered as a polyline In Kicad the bezier curves have 4 control...
wxString creator
Definition: plotter.h:595
wxSize paperSize
Definition: plotter.h:599
bool m_mirrorIsHorizontal
Definition: plotter.h:582
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL) override
Function PlotPoly.
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99