wxArt2D
parssvg.cpp
Go to the documentation of this file.
1 /*! \file svgio/src/parssvg.cpp
2  \brief a2dCanvasDocument - SVG reader via Expat
3  \author Klaas Holwerda
4 
5  Copyright: 2001-2004 (C) Klaas Holwerda
6 
7  Licence: wxWidgets licence
8 
9  RCS-ID: $Id: parssvg.cpp,v 1.109 2009/10/01 19:22:36 titato Exp $
10 */
11 
12 #include "a2dprec.h"
13 
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21 
22 #include "a2dprivate.h"
23 
24 // This file has highly nested STL-templates, and with this you cannot get around this warning
25 #ifdef _MSC_VER
26 #pragma warning(disable: 4786)
27 #endif
28 
29 #include "wx/wfstream.h"
30 #include "wx/intl.h"
31 #include "wx/log.h"
32 #include "wx/strconv.h"
33 #include <wx/tokenzr.h>
34 
35 #include "wx/docview/doccom.h"
36 #include "wx/canvas/canmod.h"
37 
38 #include "wx/svgio/parssvg.h"
39 
40 
41 using namespace std;
42 
43 // ----------------------------------------------------------------------------
44 // a2dIOHandlerSVGIn
45 // ----------------------------------------------------------------------------
46 
47 a2dIOHandlerSVGIn::a2dIOHandlerSVGIn()
48 {
49  m_fill = a2dFill();
50  m_stroke = *a2dNullSTROKE;
51  m_docClassInfo = &a2dCanvasDocument::ms_classInfo;
52 }
53 
54 a2dIOHandlerSVGIn::~a2dIOHandlerSVGIn()
55 {
56 }
57 
58 bool a2dIOHandlerSVGIn::CanLoad( a2dDocumentInputStream& stream, const wxObject* obj, wxClassInfo* docClassInfo )
59 {
60  if ( obj && !wxDynamicCast( obj, a2dCanvasDocument ) )
61  return false;
62 
63  if ( docClassInfo && m_docClassInfo && !docClassInfo->IsKindOf( m_docClassInfo ) )
64  return false;
65 
66  m_streami = &stream;
67  SeekI( 0 );
68 
69  wxString header;
70  char buf[1000];
71  int last_read = Read( buf, 1000 );
72 
73  if( last_read > 1000 )
74  {
75  last_read = 1000;
76  }
77  header = wxString( buf, wxConvUTF8, last_read );
78 
79  SeekI( 0 );
80 
81  return ( header.Contains( _T( "<?xml" ) ) && header.Contains( _T( "<!DOCTYPE" ) ) && header.Contains( _T( "<svg" ) )
82  ||
83  header.Contains( _T( "<svg" ) ) //simple file
84  );
85 }
86 
87 bool a2dIOHandlerSVGIn::Load( a2dDocumentInputStream& stream , wxObject* doc )
88 {
89  m_streami = &stream;
90  m_doc = wxStaticCast( doc, a2dCanvasDocument );
91 
92  InitializeLoad();
93 
94  bool oke;
95 
96  try
97  {
98  oke = LoadSvg( m_doc );
99  }
100  catch ( const a2dIOHandlerXMLException& e )
101  {
102  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "%s at line %d column %d" ), e.getMessage().c_str(), e.getLineNumber(), e.getColumnNumber() );
103  oke = false;
104  }
105 
106  ResetLoad();
107 
108  return oke;
109 }
110 
111 #ifdef new
112 #undef new
113 #endif
114 
115 #include <wx/hashmap.h>
116 
117 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS && wxUSE_DEBUG_NEW_ALWAYS
118 #define new new(__TFILE__,__LINE__)
119 #endif
120 
121 WX_DECLARE_STRING_HASH_MAP( wxString, StringStringHashMap );
122 static StringStringHashMap m_shapeclass;
123 static wxString m_defaultclass;
124 static double m_defaultfontsize;
125 
126 bool a2dIOHandlerSVGIn::LoadSvg( a2dCanvasDocument* doc )
127 {
128  Next();
129  Require( START_TAG, _T( "svg" ) );
130 
131  m_defaultclass = GetAttributeValue( _T( "class" ) );
132 
133  Next();
134  if ( GetTagName() == _T( "title" ) )
135  {
136  doc->SetTitle( GetContent() );
137  Next();
138  Require( END_TAG, _T( "title" ) );
139  Next();
140  }
141  if ( GetTagName() == _T( "desc" ) )
142  {
143  doc->SetDescription( GetContent() );
144  Next();
145  Require( END_TAG, _T( "desc" ) );
146  Next();
147  }
148 
149  a2dFill fill = m_fill;
150  a2dStroke stroke = m_stroke;
151  m_doc->GetDrawing()->GetRootObject()->SetFill( fill );
152  m_doc->GetDrawing()->GetRootObject()->SetStroke( stroke );
153 
154  if ( GetEventType() == START_TAG && GetTagName() == _T( "g" ) )
155  {
156  do
157  {
158  LoadSvgGroup( m_doc->GetDrawing()->GetRootObject() );
159  m_fill = m_doc->GetDrawing()->GetRootObject()->GetFill();
160  m_stroke = m_doc->GetDrawing()->GetRootObject()->GetStroke();
161  }
162  while( GetTagName() != _T( "svg" ) );
163  }
164  else
165  {
166  do
167  {
168  LoadSvgGroupElement( m_doc->GetDrawing()->GetRootObject() );
169  }
170  while( GetTagName() != _T( "svg" ) );
171  }
172  return true;
173 }
174 
175 bool a2dIOHandlerSVGIn::LoadSvgGroupElement( a2dCanvasObject* g )
176 {
177  if ( GetEventType() != START_TAG )
178  return false;
179 
180  wxString elementname = GetTagName();
181  if (
182  elementname != _T( "g" ) &&
183  elementname != _T( "a" ) &&
184  elementname != _T( "rect" ) &&
185  elementname != _T( "text" ) &&
186  elementname != _T( "circle" ) &&
187  elementname != _T( "ellipse" ) &&
188  elementname != _T( "polygon" ) &&
189  elementname != _T( "polyline" ) &&
190  elementname != _T( "line" ) &&
191  elementname != _T( "path" ) &&
192  elementname != _T( "image" )
193  )
194  {
195  if( elementname == _T( "style" ) && g == m_doc->GetDrawing()->GetRootObject() )
196  {
197  wxString style = GetContent();
198 
199  style.Trim();
200  wxStringTokenizer tkz( style, _T( "{}" ) );
201  while ( tkz.HasMoreTokens() )
202  {
203  wxString shapeclass = tkz.GetNextToken().Trim( false ).Trim();
204  wxString shapestyle = tkz.GetNextToken().Trim( false ).Trim();
205  if ( shapeclass.Length() > 1 && shapestyle.IsEmpty () == false && shapeclass[( size_t )0] == _T( '.' ) )
206  {
207  shapeclass = shapeclass.Right( shapeclass.Length() - 1 );
208  m_shapeclass[shapeclass] = shapestyle ;
209  }
210  }
211 
212  if( m_defaultclass != _T( "" ) )
213  {
214  wxString defaultstyle = m_shapeclass[m_defaultclass];
215  if( defaultstyle.Find( _T( "font-size:" ) ) >= 0 )
216  {
217  defaultstyle = defaultstyle.Right( defaultstyle.Length() - defaultstyle.Find( _T( "font-size:" ) ) - wxString( _T( "font-size:" ) ).Length() );
218  defaultstyle.ToDouble( &m_defaultfontsize );
219  }
220  }
221 
222  SkipSubTree();
223  Require( END_TAG, elementname );
224  Next();
225  return true;
226  }
227  else
228  {
229  //error or not implemented element
230  wxString parseerror = _T( "not implemented or unknown element " ) + GetTagName();
231  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: '%s' at line %d" ), parseerror.c_str(), GetCurrentLineNumber() );
232  SkipSubTree();
233  Require( END_TAG, elementname );
234  Next();
235  return true;
236  }
237  }
238 
239  if ( LoadSvgGroup( g ) ||
240  LoadSvgAnchor( g ) ||
241  LoadSvgRect( g ) ||
242  LoadSvgText( g ) ||
243  LoadSvgCircle( g ) ||
244  LoadSvgEllipse( g ) ||
245  LoadSvgPolygon( g ) ||
246  LoadSvgPolyline( g ) ||
247  LoadSvgLine( g ) ||
248  LoadSvgPath( g ) ||
249  LoadSvgImage( g )
250  )
251  {
252  }
253  else
254  {
255  //error or not implemented element
256  wxString parseerror = _T( "not implemented or unknown element " ) + GetTagName();
257  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: '%s' at line %d" ), parseerror.c_str(), GetCurrentLineNumber() );
258  //throw XmlPullParserException( "expected group element not:" + name ,GetCurrentLineNumber(), GetCurrentColumnNumber() );
259  }
260 
261  return true;
262 }
263 
264 bool a2dIOHandlerSVGIn::LoadSvgGroup( a2dCanvasObject* parent )
265 {
266  if ( GetTagName() != _T( "g" ) )
267  return false;
268 
269  a2dCanvasObject* g = new a2dCanvasObject();
270  m_currentobject = g;
271  parent->Append( m_currentobject );
272 
273  ParseSvgTransForm( m_currentobject );
274  ParseSvgStyle( m_currentobject );
275 
276  Next();
277 
278  while( 1 )
279  {
280  if ( !LoadSvgGroupElement( g ) )
281  {
282  Require( END_TAG, _T( "g" ) );
283  Next();
284  break;
285  }
286  else
287  {
288  //restore style at this level
289  m_fill = g->GetFill();
290  m_stroke = g->GetStroke();
291  }
292  }
293 
294  m_currentobject = g;
295  m_fill = g->GetFill();
296  m_stroke = g->GetStroke();
297  return true;
298 }
299 
300 bool a2dIOHandlerSVGIn::LoadSvgAnchor( a2dCanvasObject* parent )
301 {
302  if ( GetTagName() != _T( "a" ) )
303  return false;
304 
305  a2dCanvasObject* g = new a2dCanvasObject();
306  m_currentobject = g;
307  parent->Append( m_currentobject );
308 
309  ParseSvgTransForm( m_currentobject );
310  ParseSvgStyle( m_currentobject );
311  ParseSvgLink( m_currentobject );
312 
313  Next();
314 
315  while( 1 )
316  {
317  if ( !LoadSvgGroupElement( g ) )
318  {
319  Require( END_TAG, _T( "a" ) );
320  Next();
321  break;
322  }
323  else
324  {
325  //restore style at this level
326  m_fill = g->GetFill();
327  m_stroke = g->GetStroke();
328  }
329  }
330 
331  m_currentobject = g;
332  m_fill = g->GetFill();
333  m_stroke = g->GetStroke();
334 
335  return true;
336 }
337 
338 bool a2dIOHandlerSVGIn::ParseSvgTransForm( a2dCanvasObject* parent )
339 {
340  wxString str = GetAttributeValue( _T( "transform" ) );
341 
342  if ( str == _T( "" ) )
343  return false;
344 
345  wxString numstr;
346  double matrixcoef[12];
347  int nr_matrixcoef;
348 
349  wxString keywstr;
350  size_t i;
351 
352 
353  a2dAffineMatrix matrixtotal;
354  matrixtotal.Identity();
355  a2dAffineMatrix matrix;
356 
357  for ( i = 0; i < str.Len(); i++ )
358  {
359  //skip space
360  while ( wxIsspace( str[i] ) ) i++;
361 
362  nr_matrixcoef = 0;
363  keywstr.Clear();
364  //transform keyword
365  while ( i < str.Len() && wxIsalpha ( str[i] ) )
366  {
367  keywstr += str.GetChar( i );
368  i++;
369  }
370 
371  //skip space
372  while ( wxIsspace( str[i] ) ) i++;
373 
374  if ( str[i] != _T( '(' ) )
375  {
376  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: missing ( at line %d" ), GetCurrentLineNumber() );
377  return true;
378  }
379  i++;
380 
381  while ( wxIsspace( str[i] ) ) i++;
382 
383  size_t len = str.Len();
384  while ( i < len && str[i] != _T( ')' ) )
385  {
386  numstr.Clear();
387  while ( i < len && ( wxIsdigit( str[i] ) || str[i] == _T( '+' ) || str[i] == _T( '-' ) || str[i] == _T( '.' ) || str[i] == _T( 'E' ) ) )
388  {
389  numstr += str[i];//str.GetChar( i );
390  i++;
391  }
392  double val;
393  numstr.ToDouble( &val );
394  matrixcoef[nr_matrixcoef] = val;
395  nr_matrixcoef++;
396  while ( i < len && ( wxIsspace( str[i] ) || str[i] == _T( ',' ) ) ) i++;
397  }
398 
399  if ( str[i] != _T( ')' ) )
400  {
401  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: missing ) at line %d" ), GetCurrentLineNumber() );
402  return true;
403  }
404  i++;
405 
406  if ( keywstr == _T( "matrix" ) )
407  {
408  if ( nr_matrixcoef != 6 )
409  {
410  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
411  keywstr.c_str(),
412  GetCurrentLineNumber() );
413  return true;
414  }
415  matrix.SetValue( 0, 0, matrixcoef[0] );
416  matrix.SetValue( 0, 1, matrixcoef[1] );
417  matrix.SetValue( 1, 0, matrixcoef[2] );
418  matrix.SetValue( 1, 1, matrixcoef[3] );
419  matrix.SetValue( 2, 0, matrixcoef[4] );
420  matrix.SetValue( 2, 1, matrixcoef[5] );
421 
422  matrixtotal = matrixtotal * matrix;
423  }
424  else if ( keywstr == _T( "translate" ) )
425  {
426  if ( nr_matrixcoef == 1 )
427  matrixcoef[0] = 0;
428  else if ( nr_matrixcoef != 2 )
429  {
430  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
431  keywstr.c_str(),
432  GetCurrentLineNumber() );
433  return true;
434  }
435 
436  matrix.Identity();
437  matrix.Translate( matrixcoef[0] , matrixcoef[1] );
438  matrix = a2dAffineMatrix( matrixcoef[0] , matrixcoef[1] );
439  matrixtotal = matrixtotal * matrix;
440  }
441  else if ( keywstr == _T( "scale" ) )
442  {
443  if ( nr_matrixcoef == 1 )
444  matrixcoef[1] = matrixcoef[0];
445  else if ( nr_matrixcoef != 2 )
446  {
447  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
448  keywstr.c_str(),
449  GetCurrentLineNumber() );
450  return true;
451  }
452 
453  matrix.Identity();
454  matrix.Scale( matrixcoef[0] , matrixcoef[1], 0, 0 );
455  matrix = a2dAffineMatrix( 0, 0, matrixcoef[0] , matrixcoef[1] );
456 
457  matrixtotal = matrixtotal * matrix;
458  }
459  else if ( keywstr == _T( "rotate" ) )
460  {
461  if ( nr_matrixcoef != 1 )
462  {
463  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
464  keywstr.c_str(),
465  GetCurrentLineNumber() );
466  return true;
467  }
468 
469  matrix.Identity();
470  matrix.SetRotation( matrixcoef[0] );
471  matrix = a2dAffineMatrix( 0, 0, 1, 1, -matrixcoef[0] );
472  matrixtotal = matrixtotal * matrix;
473  }
474  else if ( keywstr == _T( "skewX" ) )
475  {
476  if ( nr_matrixcoef != 1 )
477  {
478  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
479  keywstr.c_str(),
480  GetCurrentLineNumber() );
481  return true;
482  }
483 
484  matrix.Identity();
485  matrix.SkewX( matrixcoef[0] );
486  matrixtotal = matrixtotal * matrix;
487  }
488  else if ( keywstr == _T( "skewY" ) )
489  {
490  if ( nr_matrixcoef != 1 )
491  {
492  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
493  keywstr.c_str(),
494  GetCurrentLineNumber() );
495  return true;
496  }
497 
498  matrix.Identity();
499  matrix.SkewY( matrixcoef[0] );
500  matrixtotal = matrixtotal * matrix;
501  }
502  else if ( keywstr == _T( "flipX" ) )
503  {
504  if ( nr_matrixcoef != 0 )
505  {
506  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
507  keywstr.c_str(),
508  GetCurrentLineNumber() );
509  return true;
510  }
511 
512  matrix.Identity();
513  matrix.Mirror( true, false );
514  matrixtotal = matrixtotal * matrix;
515  }
516  else if ( keywstr == _T( "flipY" ) )
517  {
518  if ( nr_matrixcoef != 0 )
519  {
520  wxLogWarning( _( "SVG : wrong number of arguments %s at line %d" ),
521  keywstr.c_str(),
522  GetCurrentLineNumber() );
523  return true;
524  }
525 
526  matrix.Identity();
527  matrix.Mirror( false, true );
528  matrixtotal = matrixtotal * matrix;
529  }
530  else
531  {
532  wxLogWarning( _( "SVG : invalid transform %s at line %d" ),
533  keywstr.c_str(),
534  GetCurrentLineNumber() );
535  return true;
536  }
537  }
538 
539  parent->SetTransformMatrix( matrixtotal );
540  return true;
541 }
542 
544 {
545  /*
546  if ( GetAttributeValue( _T("style") ) == _T("") )
547  {
548  parent->SetFill( a2dINHERIT_FILL );
549  parent->SetStroke( a2dINHERIT_STROKE );
550 
551  return false;
552  }
553  */
554 
555  wxString styleattrib = GetAttributeValue( _T( "style" ) ).Trim( false ).Trim();
556 
557  //if no style atrribute, a class might be used for defining the style
558  if ( styleattrib == _T( "" ) )
559  {
560  wxString classname = GetAttributeValue( _T( "class" ) );
561  if ( classname != _T( "" ) )
562  {
563  //class may contain several items
564  wxStringTokenizer tkz( classname, _T( " " ) );
565  while ( tkz.HasMoreTokens() )
566  {
567  wxString oneitem = tkz.GetNextToken();
568 
569  if( !m_shapeclass[oneitem].IsEmpty() )
570  {
571  if ( styleattrib.IsEmpty() )
572  styleattrib = m_shapeclass[oneitem] ; //contents of the class is the style.
573  else
574  styleattrib = styleattrib + wxT( ";" ) + m_shapeclass[oneitem] ; //contents of the class is the style.
575  }
576  }
577  }
578  }
579  if ( styleattrib == _T( "" ) )
580  {
581  parent->SetFill( *a2dINHERIT_FILL );
582  parent->SetStroke( *a2dINHERIT_STROKE );
583  return false;
584  }
585 
586  wxStringTokenizer tkz( styleattrib, _T( ";" ) );
587  while ( tkz.HasMoreTokens() )
588  {
589  wxStringTokenizer stylepart( tkz.GetNextToken(), _T( ":" ) );
590  wxString substyle = stylepart.GetNextToken().Trim( false ).Trim();
591  wxString value = stylepart.GetNextToken().Trim( false ).Trim();
592  double adouble;
593  long aint;
594  value.ToDouble( &adouble );
595  value.ToLong( &aint );
596  if ( substyle == _T( "fill" ) )
597  {
598  if ( value != _T( "none" ) )
599  {
600  m_fill = a2dFill( ParseSvgColour( value ) );
601  }
602  else
603  {
604  m_fill = *a2dNullFILL;
605  }
606  }
607  else if ( substyle == _T( "fill-rule" ) )
608  {
609  if ( 0 != wxDynamicCast( parent, a2dPolygonL ) )
610  {
611  a2dPolygonL* obj = wxDynamicCast( parent, a2dPolygonL );
612 
613  if ( value == _T( "evenodd" ) )
614  obj->SetFillRule( wxODDEVEN_RULE );
615  else if ( value == _T( "nonzero" ) )
616  obj->SetFillRule( wxWINDING_RULE );
617  else
618  wxLogWarning( _( "SVG unknown style fill-rule: %s at line %d" ),
619  value.c_str(),
620  GetCurrentLineNumber() );
621  }
622  }
623  else if ( substyle == _T( "stroke" ) )
624  {
625  if ( value != _T( "none" ) )
626  {
627  m_stroke = a2dStroke( ParseSvgColour( value ), a2dSTROKE_SOLID );
628  }
629  else
630  {
631  m_stroke = *a2dNullSTROKE;
632  }
633  }
634  else if ( substyle == _T( "opacity" ) )
635  {
636  m_fill.SetAlpha( aint );
637  m_stroke.SetAlpha( aint );
638  }
639  else if ( substyle == _T( "fill-opacity" ) )
640  {
641  m_fill.SetAlpha( aint );
642  }
643  else if ( substyle == _T( "stroke-opacity" ) )
644  {
645  m_stroke.SetAlpha( aint );
646  }
647  else if ( substyle == _T( "stroke-width" ) )
648  {
649  m_stroke.SetWidth( adouble );
650  }
651  else if ( substyle == _T( "stroke-linecap" ) )
652  {
653  if ( value == _T( "butt" ) )
654  m_stroke.SetCap( wxCAP_BUTT );
655  else if ( value == _T( "round" ) )
656  m_stroke.SetCap( wxCAP_ROUND );
657  else if ( value == _T( "square" ) )
658  m_stroke.SetCap( wxCAP_PROJECTING );
659  else
660  wxLogWarning( _( "SVG unknown line cap style: %s at line %d" ),
661  value.c_str(),
662  GetCurrentLineNumber() );
663  }
664  else if ( substyle == _T( "stroke-linejoin" ) )
665  {
666  if ( value == _T( "miter" ) )
667  m_stroke.SetJoin( wxJOIN_MITER );
668  else if ( value == _T( "round" ) )
669  m_stroke.SetJoin( wxJOIN_ROUND );
670  else if ( value == _T( "bevel" ) )
671  m_stroke.SetJoin( wxJOIN_BEVEL );
672  else
673  wxLogWarning( _( "SVG unknown line join style: %s at line %d" ),
674  value.c_str(),
675  GetCurrentLineNumber() );
676  }
677  else if ( substyle == _T( "font-size" ) )
678  {
679  /*!
680  \todo
681  font-size
682  */
683  a2dText* obj = wxDynamicCast( parent, a2dText );
684  if( obj )
685  {
686  if( value.Right( 2 ) == _T( "em" ) )
687  {
688  if( m_defaultfontsize < 0.1 )
689  obj->SetTextHeight( 7 );
690  else
691  obj->SetTextHeight( m_defaultfontsize * adouble );
692  }
693  else
694  obj->SetTextHeight( adouble );
695  }
696  }
697  else if ( substyle == _T( "font-family" ) )
698  {
699  /*!
700  \todo
701  font-family
702  */
703  }
704  else if ( substyle == _T( "stroke-miterlimit" ) )
705  {
706  /*!
707  \todo
708  stroke-miterlimit
709  */
710  }
711  else
712  wxLogWarning( _( "SVG unknown style: %s: %s at line %d" ),
713  substyle.c_str(), value.c_str(),
714  GetCurrentLineNumber() );
715  }
716 
717  a2dFill fill = m_fill;
718  a2dStroke stroke = m_stroke;
719 
720  parent->SetFill( fill );
721  parent->SetStroke( stroke );
722 
723  return true;
724 }
725 
726 bool a2dIOHandlerSVGIn::ParseSvgLink( a2dCanvasObject* object )
727 {
728  wxString linkattrib = GetAttributeValue( _T( "xlink:href" ) ).Trim( false ).Trim();
729  wxStringTokenizer tkz( linkattrib, _T( ";" ) );
730  while ( tkz.HasMoreTokens() )
731  {
732  wxString url = tkz.GetNextToken();
733  object->SetURI( url );
734  }
735 
736  return true;
737 }
738 
739 bool a2dIOHandlerSVGIn::LoadSvgRect( a2dCanvasObject* parent )
740 {
741  if ( GetTagName() != _T( "rect" ) )
742  return false;
743 
744  a2dRect* rect = new a2dRect();
745  m_currentobject = rect;
746  parent->Append( m_currentobject );
747 
748  ParseSvgTransForm( m_currentobject );
749  ParseSvgStyle( m_currentobject );
750 
751  a2dAffineMatrix matrixtotal = rect->GetTransformMatrix();
752  a2dAffineMatrix matrix;
753  matrix.Identity();
754  matrix.Translate( GetAttributeValueDouble( _T( "x" ) ) , GetAttributeValueDouble( _T( "y" ) ) );
755  matrixtotal = matrixtotal * matrix;
756  rect->SetTransformMatrix( matrixtotal );
757 
758  rect->SetWidth( GetAttributeValueDouble( _T( "width" ) ) );
759  rect->SetHeight( GetAttributeValueDouble( _T( "height" ) ) );
760 
761  Next();
762  Require( END_TAG, _T( "rect" ) );
763  Next();
764 
765  return true;
766 }
767 
768 bool a2dIOHandlerSVGIn::LoadSvgCircle( a2dCanvasObject* parent )
769 {
770  if ( GetTagName() != _T( "circle" ) )
771  return false;
772 
773  a2dCircle* circle = new a2dCircle();
774  m_currentobject = circle;
775  parent->Append( m_currentobject );
776 
777  ParseSvgTransForm( m_currentobject );
778  ParseSvgStyle( m_currentobject );
779 
780  a2dAffineMatrix matrixtotal = circle->GetTransformMatrix();
781  a2dAffineMatrix matrix;
782  matrix.Identity();
783  matrix.Translate( GetAttributeValueDouble( _T( "cx" ) ) , GetAttributeValueDouble( _T( "cy" ) ) );
784  matrixtotal = matrixtotal * matrix;
785  circle->SetTransformMatrix( matrixtotal );
786 
787  circle->SetRadius( GetAttributeValueDouble( _T( "r" ) ) );
788 
789  Next();
790  Require( END_TAG, _T( "circle" ) );
791  Next();
792 
793  return true;
794 }
795 
796 bool a2dIOHandlerSVGIn::LoadSvgEllipse( a2dCanvasObject* parent )
797 {
798  if ( GetTagName() != _T( "ellipse" ) )
799  return false;
800 
801  a2dEllipse* Ellipse = new a2dEllipse();
802  m_currentobject = Ellipse;
803  parent->Append( m_currentobject );
804 
805  ParseSvgTransForm( m_currentobject );
806  ParseSvgStyle( m_currentobject );
807 
808  a2dAffineMatrix matrixtotal = Ellipse->GetTransformMatrix();
809  a2dAffineMatrix matrix;
810  matrix.Identity();
811  matrix.Translate( GetAttributeValueDouble( _T( "cx" ) ) , GetAttributeValueDouble( _T( "cy" ) ) );
812  matrixtotal = matrixtotal * matrix;
813  Ellipse->SetTransformMatrix( matrixtotal );
814 
815  Ellipse->SetWidth( GetAttributeValueDouble( _T( "rx" ) ) * 2 );
816  Ellipse->SetHeight( GetAttributeValueDouble( _T( "ry" ) ) * 2 );
817 
818  Next();
819  Require( END_TAG, _T( "ellipse" ) );
820  Next();
821 
822  return true;
823 }
824 
825 bool a2dIOHandlerSVGIn::LoadSvgText( a2dCanvasObject* parent )
826 {
827  if ( GetTagName() != _T( "text" ) )
828  return false;
829 
830  a2dText* text = new a2dText( GetContent() );
831  m_currentobject = text;
832  parent->Append( m_currentobject );
833 
834  ParseSvgTransForm( m_currentobject );
835  ParseSvgStyle( m_currentobject );
836 
837  text->SetFill( *a2dTRANSPARENT_FILL );
838 
839  a2dAffineMatrix matrixtotal = text->GetTransformMatrix();
840  a2dAffineMatrix matrix;
841  matrix.Identity();
842  matrix.Translate( GetAttributeValueDouble( _T( "x" ) ) , GetAttributeValueDouble( _T( "y" ) ) );
843  matrixtotal = matrixtotal * matrix;
844  text->SetTransformMatrix( matrixtotal );
845 
846  Next();
847 
848  if( GetEventType() == END_TAG )
849  {
850  Require( END_TAG, _T( "text" ) );
851  Next();
852  }
853  else
854  {
855  wxString s = _T( "" );
856  while( GetEventType() != END_TAG || GetTagName() != _T( "text" ) )
857  {
858  if( !GetContent().IsEmpty() )
859  {
860  s = s + GetContent();
861  }
862  Next();
863  }
864  text->SetText( s );
865  Next();
866  }
867 
868 
869  return true;
870 }
871 
872 bool a2dIOHandlerSVGIn::ParsePoints( a2dVertexList* points )
873 {
874  wxString pstr = GetAttributeValue( _T( "points" ) );
875 
876  if ( pstr == _T( "" ) )
877  return false;
878 
879  wxString numstr;
880 
881  int j = 0;
882  double x = 0.0, y = 0.0;
883  size_t i;
884 
885  for ( i = 0; i < pstr.Len(); i++ )
886  {
887  if ( pstr[i] != _T( ' ' ) && pstr[i] != _T( ',' ) ) //spaces between coord and , between x and y
888  {
889  if ( j == 0 )
890  {
891  numstr.Clear();
892  while ( i < pstr.Len() && pstr[i] != _T( ' ' ) && pstr[i] != _T( ',' ) )
893  {
894  numstr += pstr.GetChar( i );
895  i++;
896  }
897  numstr.ToDouble( &x );
898  j++;
899  }
900  else
901  {
902  numstr = _T( "" );
903  while ( i < pstr.Len() && pstr[i] != _T( ' ' ) && pstr[i] != _T( ',' ) )
904  {
905  numstr += pstr.GetChar( i );
906  i++;
907  }
908  numstr.ToDouble( &y );
909  j--;
910  points->push_back( new a2dLineSegment( x, y ) );
911  }
912  }
913  }
914  return true;
915 }
916 
917 bool a2dIOHandlerSVGIn::LoadSvgPolygon( a2dCanvasObject* parent )
918 {
919  if ( GetTagName() != _T( "polygon" ) )
920  return false;
921 
922  a2dVertexList* points = new a2dVertexList();
923 
924  if ( !ParsePoints( points ) )
925  {
926  delete points;
927  wxString parseerror = _T( "points missing in polygon" );
928  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: '%s' at line %d" ), parseerror.c_str(), GetCurrentLineNumber() );
929  return true;
930  }
931 
932  a2dPolygonL* poly = new a2dPolygonL( points );
933  m_currentobject = poly;
934  parent->Append( m_currentobject );
935 
936  ParseSvgTransForm( m_currentobject );
937  ParseSvgStyle( m_currentobject );
938 
939  Next();
940  Require( END_TAG, _T( "polygon" ) );
941  Next();
942 
943  return true;
944 }
945 
946 bool a2dIOHandlerSVGIn::LoadSvgPolyline( a2dCanvasObject* parent )
947 {
948  if ( GetTagName() != _T( "polyline" ) )
949  return false;
950 
951  a2dVertexList* points = new a2dVertexList();
952 
953  if ( !ParsePoints( points ) )
954  {
955  delete points;
956  wxString parseerror = _T( "points missing in polyline" );
957  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: '%s' at line %d" ),
958  parseerror.c_str(),
959  GetCurrentLineNumber() );
960  return true;
961  }
962 
963  a2dPolylineL* poly = new a2dPolylineL( points );
964  m_currentobject = poly;
965  parent->Append( m_currentobject );
966 
967  ParseSvgTransForm( m_currentobject );
968  ParseSvgStyle( m_currentobject );
969 
970  Next();
971  Require( END_TAG, _T( "polyline" ) );
972  Next();
973 
974  return true;
975 }
976 
977 bool a2dIOHandlerSVGIn::LoadSvgLine( a2dCanvasObject* parent )
978 {
979  if ( GetTagName() != _T( "line" ) )
980  return false;
981 
982  double x1 = GetAttributeValueDouble( _T( "x1" ) );
983  double y1 = GetAttributeValueDouble( _T( "y1" ) );
984  double x2 = GetAttributeValueDouble( _T( "x2" ) );
985  double y2 = GetAttributeValueDouble( _T( "y2" ) );
986 
987  a2dSLine* line = new a2dSLine( x1, y1, x2, y2 );
988 
989  m_currentobject = line;
990  parent->Append( m_currentobject );
991 
992  ParseSvgTransForm( m_currentobject );
993  ParseSvgStyle( m_currentobject );
994 
995  Next();
996  Require( END_TAG, _T( "line" ) );
997  Next();
998 
999  return true;
1000 }
1001 
1002 
1003 #ifndef M_PI
1004 #define M_PI (3.1415926535897932384626433832795028841972)
1005 #endif
1006 
1007 //! parse svg arc
1008 /*!
1009 
1010  copy from sodipodi-0.32
1011  svg-path.c: Parse SVG path element data into bezier path.
1012 
1013  Copyright (C) 2000 Eazel, Inc.
1014  Copyright (C) 2000 Lauris Kaplinski
1015  Copyright (C) 2001 Ximian, Inc.
1016 
1017  * rsvg_path_arc: Add an RSVG arc to the path context.
1018  * \param startx startpoint x
1019  * \param starty startpoint y
1020  * \param rx Radius in x direction (before rotation).
1021  * \param ry Radius in y direction (before rotation).
1022  * \param x_axis_rotation Rotation angle for axes.
1023  * \param large_arc_flag 0 for arc length <= 180, 1 for arc >= 180.
1024  * \param sweep_flag 0 for "negative angle", 1 for "positive angle".
1025  * \param x nextpoint x
1026  * \param y nextpoint y
1027  * \param pcx New x coordinate.
1028  * \param pcy New y coordinate.
1029  * \param pangle angle
1030  *
1031  **/
1032 static void
1033 rsvg_path_arc ( double startx, double starty,
1034  double rx, double ry, double x_axis_rotation,
1035  int large_arc_flag, int sweep_flag,
1036  double x, double y,
1037  double* pcx, double* pcy,
1038  double* pangle )
1039 {
1040  double sin_th, cos_th;
1041  double a00, a01, a10, a11;
1042  double x0, y0, x1, y1, xc, yc;
1043  double d, sfactor, sfactor_sq;
1044  double th0, th1, th_arc;
1045  int n_segs;
1046 
1047  sin_th = sin ( x_axis_rotation * ( M_PI / 180.0 ) );
1048  cos_th = cos ( x_axis_rotation * ( M_PI / 180.0 ) );
1049  a00 = cos_th / rx;
1050  a01 = sin_th / rx;
1051  a10 = -sin_th / ry;
1052  a11 = cos_th / ry;
1053  x0 = a00 * startx + a01 * starty;
1054  y0 = a10 * startx + a11 * starty;
1055  x1 = a00 * x + a01 * y;
1056  y1 = a10 * x + a11 * y;
1057  /* (x0, y0) is current point in transformed coordinate space.
1058  (x1, y1) is new point in transformed coordinate space.
1059 
1060  The arc fits a unit-radius circle in this space.
1061  */
1062  d = ( x1 - x0 ) * ( x1 - x0 ) + ( y1 - y0 ) * ( y1 - y0 );
1063  sfactor_sq = 1.0 / d - 0.25;
1064  if ( sfactor_sq < 0 ) sfactor_sq = 0;
1065  sfactor = sqrt ( sfactor_sq );
1066  if ( sweep_flag == large_arc_flag ) sfactor = -sfactor;
1067  xc = 0.5 * ( x0 + x1 ) - sfactor * ( y1 - y0 );
1068  yc = 0.5 * ( y0 + y1 ) + sfactor * ( x1 - x0 );
1069  /* (xc, yc) is center of the circle. */
1070 
1071  th0 = atan2 ( y0 - yc, x0 - xc );
1072  th1 = atan2 ( y1 - yc, x1 - xc );
1073 
1074  th_arc = th1 - th0;
1075  if ( th_arc < 0 && sweep_flag )
1076  th_arc += 2 * M_PI;
1077  else if ( th_arc > 0 && !sweep_flag )
1078  th_arc -= 2 * M_PI;
1079 
1080  n_segs = ( int ) ceil ( fabs ( th_arc / ( M_PI * 0.5 + 0.001 ) ) );
1081 
1082  //*************************
1083  sin_th = sin ( x_axis_rotation * ( M_PI / 180.0 ) );
1084  cos_th = cos ( x_axis_rotation * ( M_PI / 180.0 ) );
1085  /* inverse transform compared with rsvg_path_arc */
1086  a00 = cos_th * rx;
1087  a01 = -sin_th * ry;
1088  a10 = sin_th * rx;
1089  a11 = cos_th * ry;
1090 
1091  double th_half = 0.5 * ( th1 - th0 );
1092  double t = ( 8.0 / 3.0 ) * sin ( th_half * 0.5 ) * sin ( th_half * 0.5 ) / sin ( th_half );
1093  x1 = xc + cos ( th0 ) - t * sin ( th0 );
1094  y1 = yc + sin ( th0 ) + t * cos ( th0 );
1095 
1096 // double mx = xc + cos (th0+th_arc/2) - t * sin (th0+th_arc/2);
1097 // double my = xc + sin (th0+th_arc/2) + t * cos (th0+th_arc/2);
1098 
1099  *pcx = a00 * xc + a01 * yc;
1100  *pcy = a10 * xc + a11 * yc;
1101 
1102  *pangle = th_arc;
1103 }
1104 ///
1106 {
1107  wxString buffer = GetAttributeValue( _T( "d" ) );
1108 
1109  if ( buffer == _T( "" ) )
1110  return false;
1111 
1112  unsigned int position = 0;
1113 
1114  double lastmovex = 0;
1115  double lastmovey = 0;
1116  double lastx = 0;
1117  double lasty = 0;
1118 
1119 
1120  a2dVpathSegment* prev = 0;
1121  a2dVpathSegment* seg = 0;
1122 
1123  char current;
1124 
1125  SkipSpaces( buffer, position );
1126 
1127  while ( position < buffer.Len() )
1128  {
1129  current = buffer[ position ];
1130  char command = current;
1131  position++;
1132  SkipSpaces( buffer, position );
1133  try
1134  {
1135  switch ( current )
1136  {
1137  case _T( 'z' ):
1138  case _T( 'Z' ):
1139  {
1140  lastx = lastmovex;
1141  lasty = lastmovey;
1142  prev = seg;
1143  seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
1144  points->push_back( seg );
1145  break;
1146  }
1147  case _T( 'm' ):
1148  case _T( 'M' ):
1149  {
1150  if ( command == _T( 'm' ) )
1151  lastx += ParseDouble( buffer, position );
1152  else
1153  lastx = ParseDouble( buffer, position );
1154 
1155  SkipCommaSpaces( buffer, position );
1156 
1157  if ( command == _T( 'm' ) )
1158  lasty += ParseDouble( buffer, position );
1159  else
1160  lasty = ParseDouble( buffer, position );
1161 
1162  SkipCommaSpaces( buffer, position );
1163 
1164  prev = seg;
1165  seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_MOVETO );
1166  points->push_back( seg );
1167 
1168  lastmovex = lastx;
1169  lastmovey = lasty;
1170  for ( ;; )
1171  {
1172  current = buffer[ position ];
1173  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1174  {
1175  if ( command == _T( 'm' ) )
1176  lastx += ParseDouble( buffer, position );
1177  else
1178  lastx = ParseDouble( buffer, position );
1179 
1180  SkipCommaSpaces( buffer, position );
1181 
1182  if ( command == _T( 'm' ) )
1183  lasty += ParseDouble( buffer, position );
1184  else
1185  lasty = ParseDouble( buffer, position );
1186 
1187  prev = seg;
1188  seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
1189  points->push_back( seg );
1190  }
1191  else
1192  break;
1193  SkipCommaSpaces( buffer, position );
1194  }
1195  break;
1196  }
1197  case _T( 'l' ):
1198  case _T( 'L' ):
1199  {
1200  for ( ;; )
1201  {
1202  current = buffer[ position ];
1203  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1204  {
1205  if ( command == _T( 'l' ) )
1206  lastx += ParseDouble( buffer, position );
1207  else
1208  lastx = ParseDouble( buffer, position );
1209 
1210  SkipCommaSpaces( buffer, position );
1211 
1212  if ( command == _T( 'l' ) )
1213  lasty += ParseDouble( buffer, position );
1214  else
1215  lasty = ParseDouble( buffer, position );
1216 
1217  prev = seg;
1218  seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
1219  points->push_back( seg );
1220  }
1221  else
1222  break;
1223  SkipCommaSpaces( buffer, position );
1224  }
1225  break;
1226  }
1227  case _T( 'h' ):
1228  case _T( 'H' ):
1229  {
1230  for ( ;; )
1231  {
1232  current = buffer[ position ];
1233  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1234  {
1235  if ( command == _T( 'h' ) )
1236  lastx += ParseDouble( buffer, position );
1237  else
1238  lastx = ParseDouble( buffer, position );
1239 
1240  prev = seg;
1241  seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
1242  points->push_back( seg );
1243  }
1244  else
1245  break;
1246  SkipCommaSpaces( buffer, position );
1247  }
1248  break;
1249  }
1250  case _T( 'V' ):
1251  case _T( 'v' ):
1252  {
1253  for ( ;; )
1254  {
1255  current = buffer[ position ];
1256  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1257  {
1258  if ( command == _T( 'v' ) )
1259  lasty += ParseDouble( buffer, position );
1260  else
1261  lasty = ParseDouble( buffer, position );
1262 
1263  prev = seg;
1264  seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
1265  points->push_back( seg );
1266  }
1267  else
1268  break;
1269  SkipCommaSpaces( buffer, position );
1270  }
1271  break;
1272  }
1273  case _T( 'c' ):
1274  case _T( 'C' ):
1275  case _T( 's' ):
1276  case _T( 'S' ):
1277  {
1278  double x1 = 0.0, y1 = 0.0, x2, y2, x, y;
1279  for ( ;; )
1280  {
1281  current = buffer[ position ];
1282  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1283  {
1284  if ( command == _T( 'C' ) || command == _T( 'c' ) )
1285  {
1286  x1 = ParseDouble( buffer, position );
1287  SkipCommaSpaces( buffer, position );
1288  y1 = ParseDouble( buffer, position );
1289  SkipCommaSpaces( buffer, position );
1290  }
1291  x2 = ParseDouble( buffer, position );
1292  SkipCommaSpaces( buffer, position );
1293  y2 = ParseDouble( buffer, position );
1294  SkipCommaSpaces( buffer, position );
1295  x = ParseDouble( buffer, position );
1296  SkipCommaSpaces( buffer, position );
1297  y = ParseDouble( buffer, position );
1298  SkipCommaSpaces( buffer, position );
1299 
1300  if ( command == _T( 'c' ) || command == _T( 's' ) )
1301  {
1302  x1 += lastx;
1303  y1 += lasty;
1304  x2 += lastx;
1305  y2 += lasty;
1306  x += lastx;
1307  y += lasty;
1308  }
1309 
1310  prev = seg;
1311  if ( command == _T( 'C' ) || command == _T( 'c' ) )
1312  seg = new a2dVpathCBCurveSegment( x, y, x1, y1 , x2, y2, a2dPATHSEG_CBCURVETO );
1313  else
1314  seg = new a2dVpathCBCurveSegment( prev, x, y , x2, y2, a2dPATHSEG_CBCURVETO );
1315 
1316  points->push_back( seg );
1317  lastx = x;
1318  lasty = y;
1319  }
1320  else
1321  break;
1322  SkipCommaSpaces( buffer, position );
1323  }
1324  break;
1325  }
1326  case _T( 'q' ):
1327  case _T( 'Q' ):
1328  case _T( 't' ):
1329  case _T( 'T' ):
1330  {
1331  double x1 = 0.0, y1 = 0.0, x, y;
1332  for ( ;; )
1333  {
1334  current = buffer[ position ];
1335  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1336  {
1337 
1338  if ( command == _T( 'Q' ) || command == _T( 'q' ) )
1339  {
1340  x1 = ParseDouble( buffer, position );
1341  SkipCommaSpaces( buffer, position );
1342  y1 = ParseDouble( buffer, position );
1343  SkipCommaSpaces( buffer, position );
1344  }
1345  x = ParseDouble( buffer, position );
1346  SkipCommaSpaces( buffer, position );
1347  y = ParseDouble( buffer, position );
1348  SkipCommaSpaces( buffer, position );
1349 
1350  if ( command == _T( 'q' ) || command == _T( 't' ) )
1351  {
1352  x1 += lastx;
1353  y1 += lasty;
1354  x += lastx;
1355  y += lasty;
1356  }
1357 
1358  prev = seg;
1359  if ( command == _T( 'Q' ) || command == _T( 'q' ) )
1360  seg = new a2dVpathQBCurveSegment( x, y, x1, y1, a2dPATHSEG_QBCURVETO );
1361  else
1362  seg = new a2dVpathQBCurveSegment( prev, x, y, a2dPATHSEG_QBCURVETO );
1363  points->push_back( seg );
1364  lastx = x;
1365  lasty = y;
1366  }
1367  else
1368  break;
1369  SkipCommaSpaces( buffer, position );
1370  }
1371  break;
1372  }
1373  case _T( 'a' ):
1374  case _T( 'A' ):
1375  {
1376  double rx, ry, ax, x, y;
1377  for ( ;; )
1378  {
1379  current = buffer[ position ];
1380  if ( current == wxT( '+' ) || current == wxT( '-' ) || wxIsdigit( current ) )
1381  {
1382  rx = ParseDouble( buffer, position );
1383  SkipCommaSpaces( buffer, position );
1384  ry = ParseDouble( buffer, position );
1385  SkipCommaSpaces( buffer, position );
1386  ax = ParseDouble( buffer, position );
1387  SkipCommaSpaces( buffer, position );
1388 
1389  current = buffer[ position ];
1390 
1391  bool laf = false;
1392  switch ( current )
1393  {
1394  case _T( '0' ):
1395  laf = false;
1396  break;
1397  case _T( '1' ):
1398  laf = true;
1399  break;
1400  }
1401  position++;
1402  SkipCommaSpaces( buffer, position );
1403  current = buffer[ position ];
1404 
1405  bool sf = false;
1406  switch ( current )
1407  {
1408  case _T( '0' ):
1409  sf = false;
1410  break;
1411  case _T( '1' ):
1412  sf = true;
1413  break;
1414  }
1415  position++;
1416 
1417  SkipCommaSpaces( buffer, position );
1418  x = ParseDouble( buffer, position );
1419  SkipCommaSpaces( buffer, position );
1420  y = ParseDouble( buffer, position );
1421  SkipCommaSpaces( buffer, position );
1422 
1423  if ( command == _T( 'a' ) )
1424  {
1425  x += lastx;
1426  y += lasty;
1427  }
1428 
1429  prev = seg;
1430  double xc, yc;
1431  double angle;
1432 
1433  rsvg_path_arc( lastx, lasty, rx, ry, ax, laf, sf, x, y, &xc, &yc, &angle );
1434 /// \!todo shoud be EllipticalArcSegment?
1435  seg = new a2dVpathArcSegment( prev, xc, yc, angle * 180 / M_PI );
1436 
1437  points->push_back( seg );
1438  lastx = x;
1439  lasty = y;
1440  }
1441  else
1442  break;
1443  SkipCommaSpaces( buffer, position );
1444  }
1445  break;
1446  }
1447  default:
1448  {
1449  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "expected path command: '%s' at line %d" ), buffer.c_str(), GetCurrentLineNumber() );
1450  }
1451  }
1452  }
1453  catch ( const a2dIOHandlerXMLException& e )
1454  {
1455  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "%s at line %d column %d" ), e.getMessage().c_str(), e.getLineNumber(), e.getColumnNumber() );
1456  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "expected path command: '%s' at line %d" ), buffer.c_str(), GetCurrentLineNumber() );
1457  }
1458  }
1459 
1460  return true;
1461 }
1462 
1463 bool a2dIOHandlerSVGIn::LoadSvgPath( a2dCanvasObject* parent )
1464 {
1465  if ( GetTagName() != _T( "path" ) )
1466  return false;
1467 
1468  a2dVpath* points = new a2dVpath();
1469 
1470  if ( !ParsePathPoints( points ) )
1471  {
1472  delete points;
1473  wxString parseerror = _T( "points missing in polygon" );
1474  a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _( "SVG parsing error: '%s' at line %d" ),
1475  parseerror.c_str(),
1476  GetCurrentLineNumber() );
1477  return true;
1478  }
1479 
1480  a2dVectorPath* path = new a2dVectorPath( points );
1481  m_currentobject = path;
1482  parent->Append( m_currentobject );
1483 
1484  ParseSvgTransForm( m_currentobject );
1485  ParseSvgStyle( m_currentobject );
1486 
1487  Next();
1488  Require( END_TAG, _T( "path" ) );
1489  Next();
1490 
1491  return true;
1492 }
1493 
1494 bool a2dIOHandlerSVGIn::LoadSvgImage( a2dCanvasObject* parent )
1495 {
1496  if ( GetTagName() != _T( "image" ) )
1497  return false;
1498 
1499  a2dImage* Image = new a2dImage();
1500  m_currentobject = Image;
1501  parent->Append( m_currentobject );
1502 
1503  ParseSvgTransForm( m_currentobject );
1504  ParseSvgStyle( m_currentobject );
1505 
1506  Image->Translate( GetAttributeValueDouble( _T( "x" ) ) , GetAttributeValueDouble( _T( "y" ) ) );
1507 
1508  Image->SetWidth( GetAttributeValueDouble( _T( "width" ) ) );
1509  Image->SetHeight( GetAttributeValueDouble( _T( "height" ) ) );
1510  Image->SetFilename( GetAttributeValue( _T( "xlink:href" ) ), wxBITMAP_TYPE_PNG );
1511 
1512 
1513  Next();
1514  Require( END_TAG, _T( "image" ) );
1515  Next();
1516 
1517  return true;
1518 }
1519 
1520 // ----------------------------------------------------------------------------
1521 // a2dIOHandlerSVGOut
1522 // ----------------------------------------------------------------------------
1523 
1524 a2dIOHandlerSVGOut::a2dIOHandlerSVGOut()
1525 {
1526  m_fill = a2dFill();
1527  m_stroke = *a2dNullSTROKE;
1528  m_showObject = NULL;
1529  m_ic = NULL;
1530 }
1531 
1532 a2dIOHandlerSVGOut::~a2dIOHandlerSVGOut()
1533 {
1534 }
1535 
1536 bool a2dIOHandlerSVGOut::CanSave( const wxObject* obj )
1537 {
1538  if ( !wxDynamicCast( obj, a2dCanvasDocument ) )
1539  return false;
1540  return true;
1541 }
1542 
1543 bool a2dIOHandlerSVGOut::Save( a2dDocumentOutputStream& stream, const wxObject* doc )
1544 {
1545  a2dIterC ic;
1546  m_doc = wxStaticCast( doc, a2dCanvasDocument );
1547 
1548  if ( !m_showObject )
1549  m_showObject = m_doc->GetDrawing()->GetRootObject();
1550 
1551  if ( !m_ic )
1552  {
1554  if ( drawer )
1555  {
1556  ic = a2dIterC( drawer->GetDrawingPart() );
1557  m_ic = &ic;
1558  }
1559  }
1560 
1561  wxASSERT_MSG( m_ic, wxT( "No iteration context set while writing SVG output" ) );
1562  wxASSERT_MSG( m_ic->GetDrawer2D(), wxT( "a2dIOHandlerSVGOut no a2dDrawer2D while writing SVG output" ) );
1563 
1564  InitializeSave();
1565 
1566  double Width = 1000;
1567  double Height = 1000;
1568  wxString unit = _T( "um" );
1569 
1570  bool yaxis = m_ic->GetDrawer2D()->GetYaxis();
1571 
1572  //a2dCanvasObject* root = doc->GetRootObject();
1573  a2dCanvasObject* root = m_ic->GetDrawingPart()->GetShowObject();
1574 
1575  a2dWalker_SetCheck setp( false );
1576  setp.Start( root );
1577 
1578  m_streamo = &stream;
1579 
1580  WriteStartDocument( _T( "1.0" ), _T( "UTF-8" ) , false );
1581  EndlWriteString ( _T( "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" " ) );
1582 
1583  EndlWriteString ( _T( "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> " ) );
1584 
1585  WriteStartElementAttributes( _T( "svg" ) );
1586 
1587  WriteAttribute( _T( "xmlns" ), _T( "http://www.w3.org/2000/svg" ) );
1588  WriteAttribute( _T( "xmlns:xlink" ), _T( "http://www.w3.org/1999/xlink" ) );
1589 
1590  wxString s;
1591  s.Printf ( _T( " width=\"%.2f%s\" height=\"%.2f%s\" viewBox=\"%f %f %f %f \" " ),
1592  Width, unit.c_str(), Height, unit.c_str(),
1593  m_ic->GetDrawer2D()->GetVisibleMinX(),
1594  m_ic->GetDrawer2D()->GetVisibleMinY(),
1595  m_ic->GetDrawer2D()->GetVisibleWidth(),
1596  m_ic->GetDrawer2D()->GetVisibleHeight() );
1597  //s.Printf ( "<svg width=\"%.2f%s\" height=\"%.2f%s\" viewBox=\"%f %f %f %f \"> \n",
1598  //Width,unit.c_str(),Height,unit.c_str(), root->GetBboxMinX(),root->GetBboxMinY(),
1599  // root->GetBboxWidth(),root->GetBboxHeight());
1600  WriteString( s );
1601  WriteEndAttributes();
1602 
1603  WriteElement( _T( "title" ), m_doc->GetPrintableName() );
1604  WriteElement( _T( "desc" ), m_doc->GetDescription() );
1605 
1606  WriteStartElementAttributes( _T( "g" ) );
1607  WriteAttribute( _T( "style" ), _T( "fill:black; stroke:black; stroke-width:1" ) );
1608  WriteEndAttributes();
1609 
1610  if ( yaxis )
1611  {
1612  WriteStartElementAttributes( _T( "g" ) );
1613  WriteAttribute( _T( "transform" ), _T( "scale( 1,-1)" ) );
1614  WriteEndAttributes();
1615  }
1616 
1617  m_nameMap.clear();
1618 
1619  Save( root, wxLAYER_ALL );
1620 
1621  if ( yaxis )
1622  {
1623  WriteEndElement();
1624  }
1625 
1626  WriteEndElement();
1627  WriteEndElement();
1628  WriteEndDocument();
1629 
1630  ResetSave();
1631 
1632  return true;
1633 }
1634 
1635 wxString a2dIOHandlerSVGOut::UniqueName ( wxString baseName )
1636 {
1637  if ( m_nameMap.find( baseName ) == m_nameMap.end() )
1638  {
1639  m_nameMap[baseName] = 0;
1640  }
1641  else
1642  {
1643  ++m_nameMap[baseName];
1644  }
1645  baseName.Printf( _T( "obj_%s_%d" ), baseName.c_str(), m_nameMap[baseName] );
1646  return baseName;
1647 }
1648 
1649 
1650 void a2dIOHandlerSVGOut::Save( const a2dCanvasObject* object, int layer )
1651 {
1652  int objectlayer = object->GetLayer();
1653  a2dAffineMatrix lworld = object->GetTransformMatrix();
1654  if ( layer != objectlayer && layer != wxLAYER_ALL )
1655  {
1656  return;
1657  }
1658 
1659  if( object->IsTemporary_DontSave() )
1660  return;
1661 
1662  const a2dShadowStyleProperty* shadow = object->GetShadowStyle();
1663 
1664  if ( object->GetFill().GetType() == a2dFILL_GRADIENT_FILL_LINEAR || object->GetFill().GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1665  {
1666  SaveGradient( object->GetFill(), object );
1667  }
1668 
1669  if ( shadow &&
1670  ( shadow->GetFill().GetType() == a2dFILL_GRADIENT_FILL_LINEAR || shadow->GetFill().GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1671  )
1672  {
1673  SaveGradient( shadow->GetFill(), object );
1674  }
1675 
1676  wxString s;
1677  wxString url = object->GetURI().BuildURI();
1678 
1679  if ( !url.IsEmpty() )
1680  {
1681  WriteStartElementAttributes( _T( "a" ) );
1682  WriteAttribute( _T( "xlink:href" ), url );
1683  WriteAttribute( _T( "id" ), UniqueName( object->GetName() ) );
1684  }
1685  else
1686  {
1687  WriteStartElementAttributes( _T( "g" ) );
1688  WriteAttribute( _T( "id" ), UniqueName( object->GetName() ) );
1689  }
1690 
1691  if ( !lworld.IsIdentity() )
1692  {
1693  WriteNewLine();
1694  s.Printf ( _T( "matrix( %g %g %g %g %g %g )" ),
1695  lworld.GetValue( 0, 0 ), lworld.GetValue( 0, 1 ),
1696  lworld.GetValue( 1, 0 ), lworld.GetValue( 1, 1 ),
1697  lworld.GetValue( 2, 0 ), lworld.GetValue( 2, 1 )
1698  );
1699  WriteAttribute( _T( "transform" ), s );
1700  WriteNewLine();
1701  }
1702 
1703  SetSVGStyle( object->GetFill(), object->GetStroke(), object, layer );
1704 
1705  WriteEndAttributes(); //end of attributes for style and transform
1706 
1707  if ( shadow ) //this style is seperate from layer id
1708  {
1709  double dx = cos( shadow->GetExtrudeAngle() ) * shadow->GetExtrudeDepth();
1710  double dy = sin( shadow->GetExtrudeAngle() ) * shadow->GetExtrudeDepth();
1711 
1712  WriteStartElementAttributes( _T( "g" ) );
1713  s.Printf ( _T( " %f %f " ), dx, dy );
1714  WriteAttribute( _T( "translate" ), s );
1715 
1716  SetSVGStyle( shadow->GetFill(), shadow->GetStroke(), object, layer );
1717 
1718  WriteEndAttributes(); //end of attributes for style and transform
1719 
1720  DoSave( object, layer );
1721 
1722  WriteEndElement();
1723  }
1724 
1725  DoSave( object, layer );
1726 
1727  a2dNamedPropertyList::const_iterator iter;
1728  for( iter = object->GetPropertyList().begin(); iter != object->GetPropertyList().end(); ++iter )
1729  {
1730  const a2dNamedProperty* prop = *iter;
1731  DoSaveProperty( object, prop, wxLAYER_ALL );
1732  }
1733 
1734  const a2dCanvasObjectList* childobjects = object->GetChildObjectList();
1735 
1736  if ( childobjects != wxNullCanvasObjectList )
1737  {
1738  a2dCanvasObjectList::const_iterator iter = childobjects->begin();
1739 
1740  if ( iter != childobjects->end() )
1741  {
1742 
1743  //iterate over layers if this object is meant to be drawn on a given layer at once
1744  // (m_layer != wxLAYER_ALL) If layer == wxLAYER_ALL, the iteration is done in some parent.
1745  //OR in case the object is the topobject that is displayed on the DRAWER
1746 
1747  if ( ( layer == wxLAYER_ALL || object == m_ic->GetDrawingPart()->GetShowObject() )
1748  &&
1749  m_doc->GetLayerSetup() //is there a layer setup
1750  )
1751  {
1752  unsigned int j;
1753  for ( j = 0; j < wxMAXLAYER; j++ )
1754  {
1755  a2dLayerInfo* objlayer;
1756  if ( m_ic->GetDrawingPart()->GetReverseOrder() )
1757  objlayer = m_doc->GetLayerSetup()->GetReverseOrderIndex()[j];
1758  else
1759  objlayer = m_doc->GetLayerSetup()->GetOrderIndex()[j];
1760 
1761  // non defined layers, being those that where not in the layer setup, are sorted to the end of the indexes.
1762  // So the can be skipped.
1763  if ( objlayer == wxNullLayerInfo )
1764  break;
1765 
1766  //important!
1767  //if layer is visible it will be rendered
1768  //If an object on a layer is itself invisible it will not be drawn
1769  //wxLAYER_ALL is reserved and should never be part of the layersettings
1770 
1771  //! todo this save of SVG should itself make a record of available layers,
1772  //! maybe use an internal view to do so.
1773 
1774  if ( objlayer->GetVisible() )
1775  {
1776  for( a2dCanvasObjectList::const_iterator iter2 = childobjects->begin(); iter2 != childobjects->end(); ++iter2 )
1777  {
1778  a2dCanvasObject* obj = ( *iter2 );
1779 
1780  int olayer = obj->GetLayer();
1781 
1782  if ( olayer == objlayer->GetLayer() )
1783  {
1784  Save( obj, objlayer->GetLayer() );
1785  }
1786  }
1787  }
1788  }
1789  }
1790  else
1791  {
1792  for( a2dCanvasObjectList::const_iterator iter2 = childobjects->begin(); iter2 != childobjects->end(); ++iter2 )
1793  {
1794  a2dCanvasObject* obj = ( *iter2 );
1795  int olayer = obj->GetLayer();
1796 
1797  if ( olayer == layer )
1798  {
1799  Save( obj, layer );
1800  WriteNewLine();
1801  }
1802  }
1803  }
1804  }
1805  }
1806 
1807  WriteNewLine();
1808  WriteEndElement();
1809 }
1810 
1811 void a2dIOHandlerSVGOut::SaveGradient( const a2dFill& fill, const a2dCanvasObject* object )
1812 {
1813  if ( fill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
1814  {
1815  double x1 = fill.GetStart().m_x;
1816  double y1 = fill.GetStart().m_y;
1817  double x2 = fill.GetStop().m_x;
1818  double y2 = fill.GetStop().m_y;
1819 
1820  if ( x1 == x2 && y1 == y2 )
1821  {
1822  //assume vertical gradient size of bbox
1823  x1 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMinX();
1824  y1 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMinY();
1825  x2 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMaxX();
1826  y2 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMaxY();
1827  }
1828 
1829  WriteStartElementAttributes( _T( "linearGradient" ) );
1830  WriteAttribute( _T( "id" ), fill.GetStamp() );
1831  WriteAttribute( _T( "gradientUnits" ), _T( "userSpaceOnUse" ) );
1832  WriteAttribute( _T( "x1" ), x1 );
1833  WriteAttribute( _T( "y1" ), y1 );
1834  WriteAttribute( _T( "x2" ), x2 );
1835  WriteAttribute( _T( "y2" ), y2 );
1836  WriteEndAttributes();
1837 
1838  wxString s;
1839 
1840  WriteStartElementAttributes( _T( "stop" ) );
1841  WriteAttribute( _T( "offset" ), 0 );
1842  s.Printf ( _T( "stop-color:#%s" ), ColourToHex( fill.GetColour() ).c_str() );
1843  WriteAttribute( _T( "style" ), s );
1844  WriteEndAttributes();
1845  WriteEndElement();
1846 
1847  WriteStartElementAttributes( _T( "stop" ) );
1848  WriteAttribute( _T( "offset" ), 1 );
1849  s.Printf ( _T( "stop-color:#%s" ), ColourToHex( fill.GetColour2() ).c_str() );
1850  WriteAttribute( _T( "style" ), s );
1851  WriteEndAttributes();
1852  WriteEndElement();
1853 
1854  WriteEndElement();
1855  }
1856  else if ( fill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
1857  {
1858  double radius = fill.GetRadius();
1859 
1860  if ( fill.GetRadius() == 0 )
1861  {
1862  //assume vertical gradient size of bbox
1863  radius = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetWidth() / 2.0;
1864  }
1865 
1866  WriteStartElementAttributes( _T( "radialGradient" ) );
1867  WriteAttribute( _T( "id" ), fill.GetStamp() );
1868  WriteAttribute( _T( "gradientUnits" ), _T( "userSpaceOnUse" ) );
1869 
1870  WriteAttribute( _T( "cx" ), fill.GetCenter().m_x );
1871  WriteAttribute( _T( "cy" ), fill.GetCenter().m_y );
1872  WriteAttribute( _T( "r" ), radius );
1873  WriteAttribute( _T( "xfc" ), fill.GetFocal().m_x );
1874  WriteAttribute( _T( "yfc" ), fill.GetFocal().m_y );
1875  WriteEndAttributes();
1876 
1877  wxString s;
1878 
1879  WriteStartElementAttributes( _T( "stop" ) );
1880  WriteAttribute( _T( "offset" ), 0 );
1881  s.Printf ( _T( "stop-color:#%s" ), ColourToHex( fill.GetColour() ).c_str() );
1882  WriteAttribute( _T( "style" ), s );
1883  WriteEndAttributes();
1884  WriteEndElement();
1885 
1886  WriteStartElementAttributes( _T( "stop" ) );
1887  WriteAttribute( _T( "offset" ), 1 );
1888  s.Printf ( _T( "stop-color:#%s" ), ColourToHex( fill.GetColour2() ).c_str() );
1889  WriteAttribute( _T( "style" ), s );
1890  WriteEndAttributes();
1891  WriteEndElement();
1892 
1893  WriteEndElement();
1894  }
1895 }
1896 
1897 void a2dIOHandlerSVGOut::SetSVGStyle( const a2dFill& fill, const a2dStroke& stroke, const a2dCanvasObject* object, int WXUNUSED( layer ) )
1898 {
1899  int objectlayer = object->GetLayer();
1900 
1901  a2dLayers* layers = m_doc->GetLayerSetup();
1902 
1903  a2dFill fillw;
1904  fillw = fill;
1905  a2dStroke strokew;
1906  strokew = stroke;
1907  if ( object->GetFilled() )
1908  {
1909  if ( fill.IsNoFill() )
1910  fillw = layers->GetFill( objectlayer );
1911  }
1912  else
1913  {
1914  fillw = *a2dTRANSPARENT_FILL;
1915  }
1916 
1917  if ( stroke.IsNoStroke() )
1918  strokew = layers->GetStroke( objectlayer );
1919 
1920  wxString s;
1921 
1922  if ( strokew != *a2dINHERIT_STROKE )
1923  {
1924  if ( strokew.GetType() == a2dSTROKE_ONE_COLOUR )
1925  {
1926  wxString s2, s3 ;
1927 
1928  if ( *a2dTRANSPARENT_STROKE != strokew )
1929  {
1930  s2 = _T( " stroke:#" ) + ColourToHex( strokew.GetColour() ) + _T( "; " ) ;
1931 
1932  if ( strokew.GetPixelStroke() )
1933  {
1934  double worldwidth = m_ic->GetDrawer2D()->DeviceToWorldXRel( stroke.GetWidth() );
1935  s3.Printf ( _T( "stroke-width:%f; " ), worldwidth );
1936  }
1937  else
1938  {
1939  s3.Printf ( _T( "stroke-width:%f; " ), strokew.GetWidth() );
1940  }
1941 
1942  if ( strokew.GetAlpha() < 255 )
1943  {
1944  wxString strokeAlpha;
1945  strokeAlpha.Printf
1946  (
1947  _T( "stroke-opacity:%f; " ),
1948  ( double )( strokew.GetAlpha() / 255.0 )
1949  );
1950  s3 = s3 + strokeAlpha;
1951  }
1952  if ( strokew.GetStyle() != a2dSTROKE_SOLID )
1953  {
1954  wxString strokeDash;
1955  switch ( strokew.GetStyle() )
1956  {
1957  case a2dSTROKE_DOT:
1958  strokeDash = _T( "stroke-dasharray: 0.3 0.3;" );
1959  break;
1960  case a2dSTROKE_LONG_DASH:
1961  strokeDash = _T( "stroke-dasharray: 1.5 0.5;" );
1962  break;
1963  case a2dSTROKE_SHORT_DASH:
1964  strokeDash = _T( "stroke-dasharray: 1 0.5;" );
1965  break;
1966  case a2dSTROKE_DOT_DASH:
1967  strokeDash = _T( "stroke-dasharray: 0.5 1 1.5 1;" );
1968  break;
1969  case a2dSTROKE_USER_DASH:
1970  case a2dSTROKE_TRANSPARENT:
1974  case a2dSTROKE_CROSS_HATCH:
1977  case a2dSTROKE_STIPPLE:
1980  case a2dSTROKE_OBJECTS:
1981  case a2dSTROKE_INHERIT:
1982  case a2dSTROKE_LAYER:
1983  case a2dSTROKE_NULLSTROKE:
1984  default:
1985  // No support right now
1986  break;
1987  };
1988  if ( strokeDash.Length() > 0 )
1989  {
1990  s3 = s3 + strokeDash;
1991  }
1992  }
1993  }
1994  else
1995  {
1996  s2 = _T( " stroke:none; " ) ;
1997  }
1998  s = s2 + s3;
1999 
2000  }
2001  /*
2002  else if ( 0 != wxDynamicCast( stroke, a2dCanvasObjectStroke ))
2003  {
2004  //a2dCanvasObjectStroke* obj = wxDynamicCast( stroke, a2dCanvasObjectStroke );
2005 
2006  }
2007  */
2008  }
2009 
2010  if ( fillw != *a2dINHERIT_FILL )
2011  {
2012  wxString s1( _T( "" ) );
2013  if ( fillw.GetType() == a2dFILL_ONE_COLOUR )
2014  {
2015  if ( fillw.GetStyle() != a2dFILL_TRANSPARENT )
2016  {
2017  s1 = _T( " fill:#" ) + ColourToHex( fillw.GetColour() ) + _T( "; " ) ;
2018  }
2019  else
2020  {
2021  s1 = _T( " fill:none; " ) ;
2022  }
2023  }
2024  else if ( fillw.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
2025  {
2026  wxString gradientstamp;
2027  gradientstamp.Printf( _T( "%d" ), fillw.GetStamp() );
2028 
2029  if ( fillw != *a2dTRANSPARENT_FILL )
2030  {
2031  s1 = _T( " fill-rule:nonzero; fill:url(#" ) + gradientstamp + _T( "); " );
2032  }
2033  else
2034  {
2035  s1 = _T( " fill:none; " ) ;
2036  }
2037 
2038  }
2039  else if ( fillw.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
2040  {
2041  wxString gradientstamp;
2042  gradientstamp.Printf( _T( "%d" ), fillw.GetStamp() );
2043 
2044  if ( fillw != *a2dTRANSPARENT_FILL )
2045  {
2046  s1 = _T( " fill-rule:nonzero; fill:url(#" ) + gradientstamp + _T( "); " );
2047  }
2048  }
2049  else
2050  {
2051  s1 = _T( " fill:none; " ) ;
2052  }
2053 
2054  if ( fillw.GetAlpha() < 255 )
2055  {
2056  wxString fillAlpha;
2057  fillAlpha.Printf
2058  (
2059  _T( "fill-opacity:%f; " ),
2060  ( double )( fillw.GetAlpha() / 255.0 )
2061  );
2062  s1 = s1 + fillAlpha;
2063  }
2064 
2065 
2066  s = s + s1;
2067  }
2068 
2069  a2dNamedPropertyList::const_iterator iter;
2070  for( iter = object->GetPropertyList().begin(); iter != object->GetPropertyList().end(); ++iter )
2071  {
2072  const a2dNamedProperty* prop = *iter;
2073  if ( wxDynamicCast( prop, a2dClipPathProperty ) )
2074  {
2075  wxString s1;
2076  s1.Printf ( _T( "clip-path:url(#%d)" ), prop->GetRefObject()->GetUniqueSerializationId() );
2077  s = s + s1;
2078  }
2079  }
2080 
2081  if ( !s.IsEmpty() )
2082  {
2083  *this << _T( " style = \" " ) << s << _T( " \" " );
2084  }
2085 }
2086 
2089  const a2dVertexList* vertexList,
2090  bool asPolygon,
2091  const wxString& style
2092 )
2093 {
2094 
2095  // If you want to read off the points from the SVG into wxArt2D, use the
2096  // control points as the "real" points of the control polygon.
2097 
2098  wxString s;
2099  WriteStartElementAttributes( _T( "path" ) );
2100 
2101  if ( asPolygon )
2102  {
2103  if ( style.Length() > 0 )
2104  {
2105  WriteAttribute( _T( "style" ), style );
2106  }
2107  else
2108  {
2109  WriteAttribute( _T( "style" ), _T( "fill-rule:nonzero; " ) );
2110  }
2111  }
2112  else
2113  {
2114  WriteAttribute( _T( "style" ), _T( "fill:none;" ) );
2115  }
2116  EndlWriteString( _T( "d=\"" ) );
2117 
2118 
2119  a2dVertexList::const_iterator iter = vertexList->begin();
2120 
2121  // First coordinate moveTo:
2122  a2dLineSegment* point = *iter;
2123 
2124  double x = point->m_x;
2125  double y = point->m_y;
2126  ++iter;
2127 
2128  double xOld = x;
2129  double yOld = y;
2130 
2131 
2132  point = *iter;
2133  x = point->m_x;
2134  y = point->m_y;
2135  double xFirstMidpoint = xOld + 0.5 * ( x - xOld );
2136  double yFirstMidpoint = yOld + 0.5 * ( y - yOld );
2137 
2138  if ( asPolygon )
2139  {
2140  // Polygons begin at the first midpoint, so that the curve can close.
2141  s.Printf( _T( "M %f,%f" ), xFirstMidpoint, yFirstMidpoint );
2142  EndlWriteString( s );
2143  }
2144  else
2145  {
2146  // Generate a line to the midpoint between the first point and the
2147  // first midpoint. This prevents the line endings from curving
2148  // immediately, which will look better:
2149 
2150  s.Printf( _T( "M %f,%f" ), xOld, yOld );
2151  EndlWriteString( s );
2152 
2153  s.Printf( _T( "L %f,%f" ), xFirstMidpoint, yFirstMidpoint );
2154  EndlWriteString( s );
2155  }
2156 
2157 
2158  // We now generate a series of curveTos. This will produce the same
2159  // result as the Chaikin algorithm used for the vertex list spline
2160  // routines. This is achieved by using the midpoints of the original line
2161  // segments as endpoints for our curves, while using the line segment
2162  // endpoints as the control points for the quadratic curves.
2163 
2164  for
2165  (
2166  ++iter;
2167  iter != vertexList->end();
2168  ++iter
2169  )
2170  {
2171  xOld = x;
2172  yOld = y;
2173  point = *iter;
2174  x = point->m_x;
2175  y = point->m_y;
2176 
2177  // Endpoint is the halfway point between the segments:
2178 
2179  s.Printf
2180  (
2181  _T( "Q %f,%f,%f,%f" ),
2182  xOld,
2183  yOld,
2184  xOld + 0.5 * ( x - xOld ),
2185  yOld + 0.5 * ( y - yOld )
2186  );
2187  EndlWriteString ( s );
2188  }
2189 
2190  if ( asPolygon )
2191  {
2192  // Two final curves back to the first midpoint:
2193  xOld = x;
2194  yOld = y;
2195  point = vertexList->front();
2196  x = point->m_x;
2197  y = point->m_y;
2198  s.Printf
2199  (
2200  _T( "Q %f,%f,%f,%f" ),
2201  xOld,
2202  yOld,
2203  xOld + 0.5 * ( x - xOld ),
2204  yOld + 0.5 * ( y - yOld )
2205  );
2206  EndlWriteString( s );
2207 
2208  s.Printf
2209  (
2210  _T( "Q %f,%f,%f,%f" ),
2211  x,
2212  y,
2213  xFirstMidpoint,
2214  yFirstMidpoint
2215  );
2216  EndlWriteString( s );
2217 
2218  }
2219  else
2220  {
2221  // Create the last line:
2222  s.Printf ( _T( "L %f,%f" ), x, y );
2223  EndlWriteString( s );
2224  }
2225 
2226  EndlWriteString( _T( "\"" ) ) ;
2227  WriteEndAttributes();
2228  WriteEndElement();
2229 }
2231 (
2232  const a2dVertexArray* vertexArray,
2233  bool asPolygon,
2234  const wxString& style
2235 )
2236 {
2237  a2dVertexList h;
2238  unsigned int i;
2239  for ( i = 0; i < vertexArray->size(); i++ )
2240  {
2241  h.push_back( vertexArray->Item( i )->Clone() );
2242  }
2243 
2244  CreateSVGSpline( &h, asPolygon, style );
2245 }
2246 
2247 void a2dIOHandlerSVGOut::DoSave( const a2dCanvasObject* object, int layer )
2248 {
2249  wxString s;
2250 
2251  // CANVAS OBJECT ARRAY REFERENCE
2252  if ( 0 != wxDynamicCast( object, a2dCanvasObjectArrayReference ) )
2253  {
2255 
2256  a2dAffineMatrix currentWorld = a2dIDENTITY_MATRIX;
2257 
2258  a2dAffineMatrix offsetXY;
2259 
2260  a2dAffineMatrix originalRef = obj->GetCanvasObject()->GetTransformMatrix();
2261 
2262  int i, j;
2263  for ( i = 0 ; i < obj->GetRows(); i++ )
2264  {
2265  for ( j = 0 ; j < obj->GetColumns(); j++ )
2266  {
2267  a2dAffineMatrix tworld = currentWorld;
2268  tworld *= originalRef;
2269  obj->GetCanvasObject()->SetTransformMatrix( tworld );
2270  Save( obj->GetCanvasObject(), layer );
2271  obj->GetCanvasObject()->SetTransformMatrix( originalRef );
2272 
2273  offsetXY.Translate( obj->GetHorzSpace(), 0 );
2274 
2275  currentWorld = a2dIDENTITY_MATRIX;
2276  currentWorld *= offsetXY;
2277  }
2278  //translate back (one row of columns) and add one row
2279  offsetXY.Translate( -obj->GetHorzSpace()*obj->GetColumns(), obj->GetVertSpace() );
2280  currentWorld = a2dIDENTITY_MATRIX;
2281  currentWorld *= offsetXY;
2282  }
2283  }
2284  // CANVAS OBJECT REFERENCE
2285  else if ( 0 != wxDynamicCast( object, a2dCanvasObjectReference ) )
2286  {
2288  Save( obj->GetCanvasObject(), layer );
2289  }
2290  // ORIGIN
2291  else if ( 0 != wxDynamicCast( object, a2dOrigin ) )
2292  {
2293  a2dOrigin* obj = wxDynamicCast( object, a2dOrigin );
2294 
2295  double w = ( int ) m_ic->GetDrawer2D()->DeviceToWorldXRel( obj->GetWidth() );
2296  double h = ( int ) m_ic->GetDrawer2D()->DeviceToWorldYRel( obj->GetHeight() );
2297 
2298  s.Printf ( _T( "M%f %f L %f %f" ), -w, 0.0, w, 0.0 );
2299  WriteStartElementAttributes( _T( "path" ) );
2300  WriteAttribute( _T( "d" ), s );
2301  WriteEndAttributes();
2302  WriteEndElement();
2303  s.Printf ( _T( "M %f %f L %f %f" ), 0.0, -h, 0.0, h );
2304  WriteStartElementAttributes( _T( "path" ) );
2305  WriteAttribute( _T( "d" ), s );
2306  WriteEndAttributes();
2307  WriteEndElement();
2308  }
2309  /*
2310  // These two are defined in screen coordinates, and are made for the
2311  // interface, not so much the graphics themselves. They will render
2312  // disproportionately from the other objects. We skip them as a result.
2313  // HANDLE
2314  else if (0 != wxDynamicCast( object, a2dHandle ))
2315  {
2316  a2dHandle* obj = wxDynamicCast( object, a2dHandle );
2317 
2318  //transform points to absolute
2319  double x = - obj->GetWidth()/2;
2320  double y = - obj->GetHeight()/2;
2321 
2322  WriteStartElementAttributes( _T("rect") );
2323  WriteAttribute( _T("x"), x );
2324  WriteAttribute( _T("y"), y );
2325  WriteAttribute( _T("width"), obj->GetWidth() );
2326  WriteAttribute( _T("height"), obj->GetHeight() );
2327 
2328  if ( obj->GetRadius() != 0 )
2329  WriteAttribute( _T("rx"), obj->GetRadius() );
2330 
2331  WriteEndAttributes();
2332  WriteEndElement();
2333  }
2334  // PIN
2335  else if (0 != wxDynamicCast( object, a2dPin ))
2336  {
2337  a2dPin* obj = wxDynamicCast( object, a2dPin );
2338 
2339  //transform points to absolute
2340  double x = - obj->GetWidth()/2;
2341  double y = - obj->GetHeight()/2;
2342 
2343  WriteStartElementAttributes( _T("rect") );
2344  WriteAttribute( _T("x"), x );
2345  WriteAttribute( _T("y"), y );
2346  WriteAttribute( _T("width"), obj->GetWidth() );
2347  WriteAttribute( _T("height"), obj->GetHeight() );
2348 
2349  if ( obj->GetRadius() != 0 )
2350  WriteAttribute( _T("rx"), obj->GetRadius() );
2351 
2352  WriteEndAttributes(true);
2353  }
2354  */
2355  // ARROW
2356  else if ( 0 != wxDynamicCast( object, a2dArrow ) )
2357  {
2358  a2dArrow* obj = wxDynamicCast( object, a2dArrow );
2359 
2360  a2dPoint2D* cpoints = new a2dPoint2D[5];
2361  cpoints[0].m_x = 0 ; cpoints[0].m_y = 0;
2362  cpoints[1].m_x = obj->GetL1(); cpoints[1].m_y = obj->GetBase() / 2;
2363  cpoints[2].m_x = obj->GetL2(); cpoints[2].m_y = 0;
2364  cpoints[3].m_x = obj->GetL1(); cpoints[3].m_y = -obj->GetBase() / 2;
2365 
2366  WriteStartElementAttributes( _T( "polygon" ) );
2367 
2368  wxPolygonFillMode fillStyle = wxWINDING_RULE;
2369  if ( fillStyle == wxODDEVEN_RULE )
2370  s = _T( "fill-rule:evenodd; " );
2371  else
2372  s = _T( "fill-rule:nonzero; " );
2373 
2374  WriteAttribute( _T( "style" ), s );
2375  EndlWriteString( _T( " points=\"" ) );
2376 
2377  for ( int i = 0; i < 5; i++ )
2378  {
2379  s.Printf ( _T( "%f,%f " ), cpoints [i].m_x, cpoints[i].m_y );
2380  *this << s;
2381  }
2382 
2383  EndlWriteString( _T( "\"" ) ) ;
2384  WriteEndAttributes( true ); // closes element
2385 
2386  delete [] cpoints;
2387  }
2388  // RECT_C
2389  else if ( 0 != wxDynamicCast( object, a2dRectC ) )
2390  {
2391  a2dRectC* obj = wxDynamicCast( object, a2dRectC );
2392 
2393  //transform points to absolute
2394  double x = - obj->GetWidth() / 2;
2395  double y = - obj->GetHeight() / 2;
2396 
2397  WriteStartElementAttributes( _T( "rect" ) );
2398  WriteAttribute( _T( "x" ), x );
2399  WriteAttribute( _T( "y" ), y );
2400  WriteAttribute( _T( "width" ), obj->GetWidth() );
2401  WriteAttribute( _T( "height" ), obj->GetHeight() );
2402 
2403  if ( obj->GetRadius() != 0 )
2404  WriteAttribute( _T( "rx" ), obj->GetRadius() );
2405 
2406  WriteEndAttributes( true ); // closes element
2407  }
2408  // RECT
2409  else if ( 0 != wxDynamicCast( object, a2dRect ) )
2410  {
2411  a2dRect* obj = wxDynamicCast( object, a2dRect );
2412 
2413  //transform points to absolute
2414  double x = 0;
2415  double y = 0;
2416 
2417  WriteStartElementAttributes( _T( "rect" ) );
2418  WriteAttribute( _T( "x" ), x );
2419  if ( obj->GetHeight() < 0 )
2420  {
2421  WriteAttribute( _T( "y" ), obj->GetHeight() );
2422  WriteAttribute( _T( "width" ), obj->GetWidth() );
2423  WriteAttribute( _T( "height" ), -obj->GetHeight() );
2424  }
2425  else
2426  {
2427  WriteAttribute( _T( "y" ), y );
2428  WriteAttribute( _T( "width" ), obj->GetWidth() );
2429  WriteAttribute( _T( "height" ), obj->GetHeight() );
2430  }
2431 
2432  if ( obj->GetRadius() != 0 )
2433  WriteAttribute( _T( "rx" ), obj->GetRadius() );
2434 
2435  WriteEndAttributes( true ); // closes element
2436  }
2437  // CIRCLE
2438  else if ( 0 != wxDynamicCast( object, a2dCircle ) )
2439  {
2440  a2dCircle* obj = wxDynamicCast( object, a2dCircle );
2441 
2442  WriteStartElementAttributes( _T( "circle" ) );
2443  WriteAttribute( _T( "cx" ), 0 );
2444  WriteAttribute( _T( "cy" ), 0 );
2445  WriteAttribute( _T( "r" ), obj->GetRadius() );
2446 
2447  WriteEndAttributes( true ); // closes element
2448  }
2449  // ELLIPSE
2450  else if ( 0 != wxDynamicCast( object, a2dEllipse ) )
2451  {
2452  a2dEllipse* obj = wxDynamicCast( object, a2dEllipse );
2453 
2454  double rh = obj->GetHeight() / 2 ;
2455  double rw = obj->GetWidth() / 2 ;
2456 
2457 
2458  WriteStartElementAttributes( _T( "ellipse" ) );
2459  WriteAttribute( _T( "cx" ), 0 );
2460  WriteAttribute( _T( "cy" ), 0 );
2461  WriteAttribute( _T( "rx" ), rw );
2462  WriteAttribute( _T( "ry" ), rh );
2463 
2464  WriteEndAttributes( true ); // closes element
2465  }
2466  // ELLIPTIC ARC
2467  else if ( 0 != wxDynamicCast( object, a2dEllipticArc ) )
2468  {
2469  a2dEllipticArc* obj = wxDynamicCast( object, a2dEllipticArc );
2470 
2471  //TODO rotation
2472  // pens have width, color
2473  // dashes, stipple ends, joins not implemented
2474  a2dStroke pen = object->GetStroke();
2475  /*
2476  wxColour c = pen->GetColour () ;
2477  unsigned char pr, pg, pb ;
2478  pr = c.Red ();
2479  pg = c.Green ();
2480  pb = c. Blue ();
2481  */
2482  wxString s, s1, s2, s3 ;
2483 
2484  a2dFill fill = object->GetFill();
2485 
2486  double xc = 0;
2487  double yc = 0;
2488 
2489  double rx = obj->GetHeight() / 2 ;
2490  double ry = obj->GetWidth() / 2 ;
2491 
2492  double xs, ys, xe, ye ;
2493  xs = xc + rx * cos ( wxDegToRad( obj->GetStart() ) ) ;
2494  xe = xc + rx * cos ( wxDegToRad( obj->GetEnd() ) ) ;
2495  ys = yc - ry * sin ( wxDegToRad( obj->GetStart() ) ) ; //coordinate system y axis goes down
2496  ye = yc - ry * sin ( wxDegToRad( obj->GetEnd() ) ) ;
2497 
2498  ///now same as circle arc...
2499 
2500  double theta1 = atan2( yc - ys, xs - xc );
2501  if ( theta1 < 0 ) theta1 = theta1 + wxPI * 2;
2502  double theta2 = atan2( yc - ye, xe - xc );
2503  if ( theta2 < 0 ) theta2 = theta2 + wxPI * 2;
2504  if ( theta2 < theta1 ) theta2 = theta2 + wxPI * 2 ;
2505 
2506  bool fArc; // flag for large or small arc 0 means less than 180 degrees
2507  if ( fabs( ( theta2 - theta1 ) ) > wxPI ) fArc = true; else fArc = false;
2508 
2509  bool fSweep = false; // flag for sweep always 0
2510 
2511  if ( fill != *a2dTRANSPARENT_FILL )
2512  {
2513  WriteStartElementAttributes( _T( "path" ) );
2514 
2515  //first only filled
2516  s.Printf ( _T( "M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z" ),
2517  xs, ys, rx, ry, fArc ? _T( "1" ) : _T( "0" ) , fSweep ? _T( "1" ) : _T( "0" ), xe, ye, xc, yc );
2518  WriteAttribute( _T( "d" ), s );
2519  WriteAttribute( _T( "style" ), _T( "stroke:none; " ) );
2520  WriteEndAttributes();
2521  WriteEndElement();
2522  }
2523 
2524  if ( pen != *a2dTRANSPARENT_STROKE )
2525  {
2526  //again only outline
2527  WriteStartElementAttributes( _T( "path" ) );
2528 
2529  //first only filled
2530  s.Printf ( _T( "M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z" ),
2531  xs, ys, rx, ry, fArc ? _T( "1" ) : _T( "0" ) , fSweep ? _T( "1" ) : _T( "0" ), xe, ye, xc, yc );
2532  //NON closed outline
2533  //s.Printf ( "M%f %f A%f %f 0.0 %f %f %f %f",
2534  // xs, ys, rx, ry, fArc? "1": "0" , fSweep? "1": "0",xe, ye );
2535 
2536  WriteAttribute( _T( "d" ), s );
2537  WriteAttribute( _T( "style" ), _T( "fill:none; " ) );
2538  WriteEndAttributes();
2539  WriteEndElement();
2540 
2541 
2542  }
2543  }
2544  // ARC
2545  else if ( 0 != wxDynamicCast( object, a2dArc ) )
2546  {
2547  a2dArc* obj = wxDynamicCast( object, a2dArc );
2548 
2549  //TODO rotation
2550  // pens have width, color
2551  // dashes, stipple ends, joins not implemented
2552  a2dStroke pen = object->GetStroke();
2553 
2554  wxString s, s1, s2, s3 ;
2555 
2556  a2dFill fill = object->GetFill();
2557 
2558  double xc = 0;
2559  double yc = 0;
2560 
2561  double dx = obj->GetX1();
2562  double dy = obj->GetY1();
2563  double radius = sqrt( dx * dx + dy * dy );
2564 
2565  double start = wxRadToDeg( atan2( dy, dx ) );
2566 
2567  dx = obj->GetX2();
2568  dy = obj->GetY2();
2569  double end = wxRadToDeg( atan2( dy, dx ) );
2570 
2571  double rx = radius;
2572  double ry = radius;
2573 
2574  double xs, ys, xe, ye ;
2575  if ( m_ic->GetDrawer2D()->GetYaxis() )
2576  {
2577  xs = xc + rx * cos ( wxDegToRad( start ) ) ;
2578  xe = xc + rx * cos ( wxDegToRad( end ) ) ;
2579  ys = yc + ry * sin ( wxDegToRad( start ) ) ;
2580  ye = yc + ry * sin ( wxDegToRad( end ) ) ;
2581  }
2582  else
2583  {
2584  xe = xc + rx * cos ( wxDegToRad( start ) ) ;
2585  xs = xc + rx * cos ( wxDegToRad( end ) ) ;
2586  ye = yc + ry * sin ( wxDegToRad( start ) ) ; //coordinate system y axis goes down
2587  ys = yc + ry * sin ( wxDegToRad( end ) ) ;
2588  }
2589 
2590  ///now same as circle arc...
2591 
2592  double theta1 = atan2( yc - ys, xs - xc );
2593  if ( theta1 < 0 ) theta1 = theta1 + wxPI * 2;
2594  double theta2 = atan2( yc - ye, xe - xc );
2595  if ( theta2 < 0 ) theta2 = theta2 + wxPI * 2;
2596  if ( theta2 < theta1 ) theta2 = theta2 + wxPI * 2 ;
2597 
2598  bool fArc; // flag for large or small arc 0 means less than 180 degrees
2599  if ( fabs( ( theta2 - theta1 ) ) > wxPI ) fArc = true; else fArc = false;
2600 
2601  bool fSweep = false; // flag for sweep always 0
2602 
2603  if ( fill != *a2dTRANSPARENT_FILL )
2604  {
2605  WriteStartElementAttributes( _T( "path" ) );
2606 
2607  //first only filled
2608  s.Printf ( _T( "M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z" ),
2609  xs, ys, rx, ry, fArc ? _T( "1" ) : _T( "0" ) , fSweep ? _T( "1" ) : _T( "0" ), xe, ye, xc, yc );
2610  WriteAttribute( _T( "d" ), s );
2611  WriteAttribute( _T( "style" ), _T( "stroke:none; " ) );
2612  WriteEndAttributes();
2613  WriteEndElement();
2614  }
2615 
2616  if ( pen != *a2dTRANSPARENT_STROKE )
2617  {
2618  //again only outline
2619  WriteStartElementAttributes( _T( "path" ) );
2620 
2621  //first only filled
2622  s.Printf ( _T( "M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z" ),
2623  xs, ys, rx, ry, fArc ? _T( "1" ) : _T( "0" ) , fSweep ? _T( "1" ) : _T( "0" ), xe, ye, xc, yc );
2624  //NON closed outline
2625  //s.Printf ( "M%f %f A%f %f 0.0 %f %f %f %f",
2626  // xs, ys, rx, ry, fArc,fSweep,xe, ye );
2627 
2628  WriteAttribute( _T( "d" ), s );
2629  WriteAttribute( _T( "style" ), _T( "fill:none; " ) );
2630  WriteEndAttributes();
2631  WriteEndElement();
2632  }
2633  }
2634  // ENDS LINE
2635  else if ( 0 != wxDynamicCast( object, a2dEndsLine ) )
2636  {
2637  a2dEndsLine* obj = wxDynamicCast( object, a2dEndsLine );
2638 
2639  double x1 = obj->GetPosX1( false );
2640  double y1 = obj->GetPosY1( false );
2641  double x2 = obj->GetPosX2( false );
2642  double y2 = obj->GetPosY2( false );
2643  double xscale = obj->GetEndScaleX();
2644  double yscale = obj->GetEndScaleY();
2645 
2646  WriteStartElementAttributes( _T( "path" ) );
2647  s.Printf ( _T( "M%f %f L%f %f" ), x1, y1, x2, y2 );
2648  WriteAttribute( _T( "d" ), s );
2649  WriteEndAttributes();
2650  WriteEndElement();
2651 
2652  if ( obj->GetBegin() )
2653  {
2654  double dx, dy;
2655  dx = x2 - x1;
2656  dy = y2 - y1;
2657  double ang1;
2658  if ( !dx && !dy )
2659  ang1 = 0;
2660  else
2661  ang1 = wxRadToDeg( atan2( dy, dx ) );
2662 
2663  a2dAffineMatrix lworld;
2664  //clockwise rotation so minus
2665  lworld.Scale( xscale, yscale, 0, 0 );
2666  lworld.Rotate( -ang1 );
2667  lworld.Translate( x1, y1 );
2668 
2669  WriteStartElementAttributes( _T( "g" ) );
2670  s.Printf ( _T( "matrix( %g %g %g %g %g %g )" ),
2671  lworld.GetValue( 0, 0 ), lworld.GetValue( 0, 1 ),
2672  lworld.GetValue( 1, 0 ), lworld.GetValue( 1, 1 ),
2673  lworld.GetValue( 2, 0 ), lworld.GetValue( 2, 1 )
2674  );
2675  WriteAttribute( _T( "transform" ), s );
2676  WriteEndAttributes();
2677 
2678  Save( obj->GetBegin(), layer );
2679 
2680  WriteEndElement();
2681  }
2682 
2683  if ( obj->GetEnd() )
2684  {
2685  double dx, dy;
2686  dx = x2 - x1;
2687  dy = y2 - y1;
2688  double ang2;
2689  if ( !dx && !dy )
2690  ang2 = 0;
2691  else
2692  ang2 = wxRadToDeg( atan2( -dy, -dx ) );
2693 
2694  a2dAffineMatrix lworld;
2695  //clockwise rotation so minus
2696  lworld.Scale( xscale, yscale, 0, 0 );
2697  lworld.Rotate( -ang2 );
2698  lworld.Translate( x2, y2 );
2699 
2700  WriteStartElementAttributes( _T( "g" ) );
2701  s.Printf ( _T( "matrix( %g %g %g %g %g %g )" ),
2702  lworld.GetValue( 0, 0 ), lworld.GetValue( 0, 1 ),
2703  lworld.GetValue( 1, 0 ), lworld.GetValue( 1, 1 ),
2704  lworld.GetValue( 2, 0 ), lworld.GetValue( 2, 1 )
2705  );
2706  WriteAttribute( _T( "transform" ), s );
2707  WriteEndAttributes();
2708 
2709  Save( obj->GetEnd(), layer );
2710 
2711  WriteEndElement();
2712  }
2713  }
2714  // SLINE
2715  else if ( 0 != wxDynamicCast( object, a2dSLine ) )
2716  {
2717  a2dSLine* obj = wxDynamicCast( object, a2dSLine );
2718 
2719  WriteStartElementAttributes( _T( "path" ) );
2720  s.Printf ( _T( "M%f %f L%f %f" ), obj->GetPosX1( false ), obj->GetPosY1( false ), obj->GetPosX2( false ), obj->GetPosY2( false ) );
2721  WriteAttribute( _T( "d" ), s );
2722  WriteEndAttributes();
2723  WriteEndElement();
2724  }
2725  // IMAGE
2726  else if ( 0 != wxDynamicCast( object, a2dImage ) )
2727  {
2728  a2dImage* obj = wxDynamicCast( object, a2dImage );
2729 
2730  double width = obj->GetWidth();
2731  double height = obj->GetHeight();
2732 
2733  //transform points to absolute
2734  double x = -width / 2;
2735  double y = -height / 2;
2736 
2737  WriteStartElementAttributes( _T( "image" ) );
2738  WriteAttribute( _T( "x" ), x );
2739  WriteAttribute( _T( "y" ), y );
2740  WriteAttribute( _T( "width" ), width );
2741  WriteAttribute( _T( "height" ), height );
2742  WriteAttribute( _T( "xlink:href" ), obj->GetFilename() );
2743  WriteEndAttributes();
2744  WriteEndElement();
2745  }
2746  // TEXT
2747  else if ( 0 != wxDynamicCast( object, a2dText ) )
2748  {
2749  a2dText* obj = wxDynamicCast( object, a2dText );
2750 
2751  //a2dStroke pen = object->GetStroke();
2752 
2753  const a2dFontInfo& font = obj->GetFont().GetFontInfo();
2754 
2755  wxString fontFamily =
2756  ( font.GetName().Length() > 0 )
2757  ? font.GetName()
2758  : _T( "Verdana, LiberationSans, sans-serif" );
2759 
2760  wxString fontStyleBold =
2761  ( font.GetStyle().Lower().Find( _T( "bold" ) ) != -1 )
2762  ? _T( "font-weight:bold; " )
2763  : ( font.GetStyle().Lower().Find( _T( "light" ) ) != -1 )
2764  ? _T( "font-weight:lighter; " )
2765  : _T( "" );
2766 
2767  wxString fontStyleItalic =
2768  ( font.GetStyle().Lower().Find( _T( "italic" ) ) != -1 )
2769  ? _T( "font-style:italic; " )
2770  : ( font.GetStyle().Lower().Find( _T( "slant" ) ) != -1 )
2771  ? _T( "font-style:oblique; " )
2772  : _T( "" );
2773 
2774 
2775  wxString alignmentH =
2776  ( obj->GetAlignment() & ( wxMAXX ) )
2777  ? _T( "end" ) // right
2778  : ( obj->GetAlignment() & ( wxMINX ) )
2779  ? _T( "start" ) // left
2780  : _T( "middle" ); // center, default
2781 
2782  wxString alignmentV =
2783  ( obj->GetAlignment() & ( wxMINY ) )
2784  ? _T( "-100%" )
2785  : ( obj->GetAlignment() & ( wxMIDY ) )
2786  ? _T( "-50%" )
2787  : _T( "0%" ); // top, default
2788 
2789  wxString color = ColourToHex( obj->GetStroke().GetColour() );
2790 
2791  s.Printf
2792  (
2793  _T( "font-family:%s; " )
2794  _T( "font-size:%fpt; " ) // Remember the "pt"
2795  _T( "fill:#%s; " )
2796  _T( "stroke:#%s; " )
2797  _T( "text-anchor:%s; " ) // For h-align
2798  _T( "baseline-shift:%s; " ) // For v-align
2799  _T( "%s%s" ),
2800  fontFamily.c_str(),
2801  obj->GetTextHeight(),
2802 #if wxCHECK_VERSION(2, 9, 0)
2803  color.GetData().AsChar(),
2804  color.GetData().AsChar(),
2805  alignmentH.GetData().AsChar(),
2806  alignmentV.GetData().AsChar(),
2807  fontStyleBold.GetData().AsChar(),
2808  fontStyleItalic.GetData().AsChar()
2809 #else
2810  color.c_str(),
2811  color.c_str(),
2812  alignmentH.c_str(),
2813  alignmentV.c_str(),
2814  fontStyleBold.c_str(),
2815  fontStyleItalic.c_str()
2816 #endif
2817  );
2818 
2819  WriteStartElementAttributes( _T( "text" ) );
2820  WriteAttribute( _T( "x" ), 0 );
2821  WriteAttribute( _T( "y" ), 0 );
2822  WriteAttribute( _T( "style" ), s );
2823  WriteEndAttributes();
2824  /*!
2825  \todo
2826  Multiline text (tspan)
2827  */
2828  WriteContent( obj->GetText() );
2829  WriteEndElement();
2830  }
2831  // POLYLINE L NEW
2832  else if ( 0 != wxDynamicCast( object, a2dPolylineL ) )
2833  {
2834  a2dPolylineL* obj = wxDynamicCast( object, a2dPolylineL );
2835 
2836  a2dVertexList* points = obj->GetSegments();
2837 
2838  if ( obj->GetSpline() && ( points->size() > 2 ) )
2839  {
2840  CreateSVGSpline ( points );
2841  }
2842  else
2843  {
2844 
2845  // Polyline (should be in else statement):
2846  WriteStartElementAttributes( _T( "polyline" ) );
2847 
2848  WriteAttribute( _T( "style" ), _T( "fill:none;" ) );
2849  EndlWriteString( _T( " points=\"" ) );
2850 
2851  unsigned int i = 0;
2852  for
2853  (
2854  a2dVertexList::iterator iter = points->begin();
2855  iter != points->end();
2856  ++iter
2857  )
2858  {
2859  a2dLineSegment* point = *iter;
2860  s.Printf ( _T( "%f,%f " ), point->m_x, point->m_y );
2861  if ( i % 6 == 0 )
2862  WriteNewLine();
2863  WriteString( s ) ;
2864  i++;
2865  }
2866 
2867  EndlWriteString( _T( "\"" ) ) ;
2868  WriteEndAttributes();
2869  WriteEndElement();
2870  }
2871 
2872  // Beginning and end graphics:
2873 
2874 
2875  double xscale = obj->GetEndScaleX();
2876  double yscale = obj->GetEndScaleY();
2877 
2878  if ( obj->GetBegin() )
2879  {
2880  a2dVertexList::iterator iter = points->begin();
2881  a2dLineSegment* point1 = *iter;
2882  iter++;
2883  a2dLineSegment* point2 = *iter;
2884 
2885  double dx, dy;
2886  dx = point2->m_x - point1->m_x;
2887  dy = point2->m_y - point1->m_y;
2888 
2889  double ang1;
2890  if ( !dx && !dy )
2891  ang1 = 0;
2892  else
2893  ang1 = wxRadToDeg( atan2( dy, dx ) );
2894 
2895  a2dAffineMatrix lworld;
2896  //clockwise rotation so minus
2897  lworld.Scale( xscale, yscale, 0, 0 );
2898  lworld.Rotate( -ang1 );
2899  lworld.Translate( point1->m_x, point1->m_y );
2900 
2901  WriteStartElementAttributes( _T( "g" ) );
2902  s.Printf ( _T( "matrix( %g %g %g %g %g %g )" ),
2903  lworld.GetValue( 0, 0 ), lworld.GetValue( 0, 1 ),
2904  lworld.GetValue( 1, 0 ), lworld.GetValue( 1, 1 ),
2905  lworld.GetValue( 2, 0 ), lworld.GetValue( 2, 1 )
2906  );
2907  WriteAttribute( _T( "transform" ), s );
2908  WriteEndAttributes();
2909 
2910  Save( obj->GetBegin(), layer );
2911 
2912  WriteEndElement();
2913  }
2914 
2915  if ( obj->GetEnd() )
2916  {
2917  a2dVertexList::reverse_iterator iter = points->rbegin();
2918  a2dLineSegment* point1 = *iter;
2919  iter++;
2920  a2dLineSegment* point2 = *iter;
2921 
2922  double dx, dy;
2923  dx = point2->m_x - point1->m_x;
2924  dy = point2->m_y - point1->m_y;
2925  double ang2;
2926  if ( !dx && !dy )
2927  ang2 = 0;
2928  else
2929  ang2 = wxRadToDeg( atan2( dy, dx ) );
2930 
2931  a2dAffineMatrix lworld;
2932  //clockwise rotation so minus
2933  lworld.Scale( xscale, yscale, 0, 0 );
2934  lworld.Rotate( -ang2 );
2935  lworld.Translate( point1->m_x, point1->m_y );
2936 
2937  WriteStartElementAttributes( _T( "g" ) );
2938  s.Printf ( _T( "matrix( %g %g %g %g %g %g )" ),
2939  lworld.GetValue( 0, 0 ), lworld.GetValue( 0, 1 ),
2940  lworld.GetValue( 1, 0 ), lworld.GetValue( 1, 1 ),
2941  lworld.GetValue( 2, 0 ), lworld.GetValue( 2, 1 )
2942  );
2943  WriteAttribute( _T( "transform" ), s );
2944  WriteEndAttributes();
2945 
2946  Save( obj->GetEnd(), layer );
2947 
2948  WriteEndElement();
2949  }
2950 
2951  }
2952  // POLYGON (LIST)
2953  else if ( 0 != wxDynamicCast( object, a2dPolygonL ) )
2954  {
2955  a2dPolygonL* obj = wxDynamicCast( object, a2dPolygonL );
2956 
2957  a2dVertexList* points = obj->GetSegments();
2958  wxPolygonFillMode fillStyle = wxWINDING_RULE;
2959  if ( fillStyle == wxODDEVEN_RULE )
2960  s = _T( "fill-rule:evenodd; " );
2961  else
2962  s = _T( "fill-rule:nonzero; " );
2963 
2964  if ( obj->GetSpline() && ( points->size() > 2 ) )
2965  {
2966  CreateSVGSpline( points, true, s );
2967  }
2968  else
2969  {
2970  WriteStartElementAttributes( _T( "polygon" ) );
2971 
2972  WriteAttribute( _T( "style" ), s );
2973  WriteNewLine();
2974  EndlWriteString( _T( " points=\"" ) );
2975 
2976  unsigned int i = 0;
2977  for
2978  (
2979  a2dVertexList::iterator iter = points->begin();
2980  iter != points->end();
2981  ++iter
2982  )
2983  {
2984  a2dLineSegment* seg = *iter;
2985  if ( i % 6 == 0 )
2986  WriteNewLine();
2987  s.Printf ( _T( "%f,%f " ), seg->m_x, seg->m_y );
2988  WriteString( s );
2989  i++;
2990  }
2991  WriteString( _T( "\"" ) ) ;
2992  WriteNewLine();
2993  WriteEndAttributes();
2994  WriteEndElement();
2995  }
2996  }
2997  // VECTOR PATH
2998  else if ( 0 != wxDynamicCast( object, a2dVectorPath ) )
2999  {
3000  a2dVectorPath* obj = wxDynamicCast( object, a2dVectorPath );
3001 
3002  WriteStartElementAttributes( _T( "path" ) );
3003  WriteString( _T( " d=\"" ) );
3004 
3005  unsigned int i;
3006  for ( i = 0; i < obj->GetCount(); i++ )
3007  {
3008  a2dVpathSegment* seg = obj->GetSegments()->Item( i );
3009 
3010  switch ( seg->m_type )
3011  {
3012  case a2dPATHSEG_MOVETO:
3013  {
3014  s.Printf ( _T( "M %f %f " ), seg->m_x1, seg->m_y1 );
3015  break;
3016  }
3017  case a2dPATHSEG_LINETO:
3018  {
3019  s.Printf ( _T( "L %f %f " ), seg->m_x1, seg->m_y1 );
3020  break;
3021  }
3023  {
3024  //TODO how to emulate this
3025  s.Printf ( _T( "L %f %f " ), seg->m_x1, seg->m_y1 );
3026  break;
3027  }
3028 
3029  case a2dPATHSEG_CBCURVETO:
3030  {
3032  s.Printf ( _T( "C %g %g %g %g %g %g " ), cseg->m_x2, cseg->m_y2, cseg->m_x3, cseg->m_y3, cseg->m_x1, cseg->m_y1 );
3033  break;
3034  }
3036  {
3038  s.Printf ( _T( "C %g %g %g %g %g %g " ), cseg->m_x2, cseg->m_y2, cseg->m_x3, cseg->m_y3, cseg->m_x1, cseg->m_y1 );
3039  break;
3040  }
3041 
3042  case a2dPATHSEG_QBCURVETO:
3043  {
3045  s.Printf ( _T( "T %f %f %f %f " ), cseg->m_x2, cseg->m_y2, cseg->m_x1, cseg->m_y1 );
3046  break;
3047  }
3049  {
3051  s.Printf ( _T( "T %f %f %f %f " ), cseg->m_x2, cseg->m_y2, cseg->m_x1, cseg->m_y1 );
3052  break;
3053  }
3054 
3055  case a2dPATHSEG_ARCTO:
3056  {
3057  //TODO how to emulate this
3058  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg;
3059  s.Printf ( _T( "T %f %f %f %f " ), cseg->m_x2, cseg->m_y2, cseg->m_x1, cseg->m_y1 );
3060  break;
3061  }
3063  {
3064  //TODO how to emulate this
3065  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg;
3066  s.Printf ( _T( "T %f %f %f %f " ), cseg->m_x2, cseg->m_y2, cseg->m_x1, cseg->m_y1 );
3067  break;
3068  }
3069  default:
3070  break;
3071  }
3072 
3073  WriteString( s );
3074 
3075  switch ( seg->GetClose() )
3076  {
3077  case a2dPATHSEG_END_CLOSED:
3078  {
3079  WriteString( _T( " Z" ) );
3080  break;
3081  }
3083  {
3084  //TODO ignore nostroke for the moment
3085  WriteString( _T( " Z" ) );
3086  break;
3087  }
3088  default:
3089  break;
3090  }
3091 
3092  if ( i % 2 == 0 )
3093  WriteNewLine();
3094  }
3095 
3096  WriteString( _T( "\"" ) ) ;
3097  WriteEndAttributes();
3098  WriteEndElement();
3099  }
3100 
3101 }
3102 
3103 void a2dIOHandlerSVGOut::DoSaveProperty( const a2dCanvasObject* WXUNUSED( object ), const a2dNamedProperty* property, int layer )
3104 {
3105  wxString s;
3106  if ( 0 != wxDynamicCast( property, a2dClipPathProperty ) )
3107  {
3109 
3110  //we have a clip path
3111  if ( prop->GetClipObject() )
3112  {
3113  WriteStartElement( _T( "defs" ) );
3114  WriteStartElementAttributes( _T( "clipPath" ) );
3115  WriteAttribute( _T( "id" ), prop->GetRefObject()->GetUniqueSerializationId() );
3116 
3117  //oh ooh next not possible since clippath does not understand groups within,
3118  //only plain shapes!
3119  //Save( indent+2, stream, prop->GetClip(), layer );
3120 
3121  a2dAffineMatrix lworld = prop->GetClipObject()->GetTransformMatrix();
3122  if ( !lworld.IsIdentity() )
3123  {
3124  s.Printf ( _T( "matrix( %g %g %g %g %g %g )" ),
3125  lworld.GetValue( 0, 0 ), lworld.GetValue( 0, 1 ),
3126  lworld.GetValue( 1, 0 ), lworld.GetValue( 1, 1 ),
3127  lworld.GetValue( 2, 0 ), lworld.GetValue( 2, 1 )
3128  );
3129  WriteAttribute( _T( "transform" ), s );
3130  }
3131 
3132  SetSVGStyle( prop->GetClipObject()->GetFill(), prop->GetClipObject()->GetStroke(), prop->GetClipObject(), layer );
3133  WriteEndAttributes();
3134 
3135  a2dCanvasObjectList* childobjects = prop->GetClipObject()->GetChildObjectList();
3136 
3137  //the next is a workaround which should work for valid SVG i think.
3138  //THE PROBLEM is that it can only be one level deep.
3139  //SO either it is the clipobject itself or when it is a group it is the children of the object
3140  //which defines the clip.
3141  //This misses the case of both havin children and the object itself.
3142  if ( childobjects != wxNullCanvasObjectList )
3143  {
3144  forEachIn( a2dCanvasObjectList, childobjects )
3145  DoSave( ( *iter ), layer );
3146  }
3147 
3148  WriteEndElement();
3149  WriteEndElement();
3150  }
3151 
3152  if ( prop->GetVisible() )
3153  {
3154  SetSVGStyle( prop->GetClipObject()->GetFill(), prop->GetClipObject()->GetStroke(), prop->GetClipObject(), layer );
3155  Save( prop->GetClipObject(), layer );
3156  }
3157 
3158  }
3159  else if ( 0 != wxDynamicCast( property, a2dProperty ) &&
3160  property->GetCanRender() && property->GetVisible() )
3161  {
3162  Save( ( a2dCanvasObject* ) property->GetRefObject(), layer );
3163  }
3164 }
a2dCanvasObject * GetCanvasObject()
Definition: recur.cpp:104
set check on a2dObject flag false or true
Definition: algos.h:665
a2dCircle at x,y, and with radius
Definition: canprim.h:554
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
bool GetFilled() const
Definition: canobj.h:1476
a2dAffineMatrix & Mirror(bool y=true, bool x=false)
mirror a matrix in x, y
Definition: afmatrix.cpp:396
For exceptions thrown while parsing XML files.
Definition: genxmlpars.h:36
(In) Visible property that can be added to Docview Objects.
Definition: gen.h:1785
double GetEndScaleY()
scale begin and end object with this factor in X
Definition: polygon.h:398
double GetWidth() const
get width of image
Definition: canimage.h:111
#define wxDynamicCast(obj, className)
Define wxDynamicCast so that it will give a compiler error for unrelated types.
Definition: gen.h:75
Base class for all types of strokes, understood by a2dDrawer2D classes.
Definition: stylebase.h:378
double GetPosX2(bool transform=true) const
Get (transformed) position of X2.
Definition: canprim.cpp:3865
bool IsNoStroke() const
Definition: stylebase.h:510
a2dCanvasObjectReference is a reference to any a2dCanvasObject derived class.
Definition: recur.h:53
SVG loader and saver of a wxCanvasDocument.
Quadratic Bezier curve.
Definition: polyver.h:984
const wxString & GetName() const
Get name of font, e.g. Arial.
Definition: stylebase.h:717
virtual bool IsTemporary_DontSave() const
Check if this is a temporary object, which should not be saved.
Definition: canobj.cpp:6365
virtual wxString GetName() const
Returns the name of this object, if no name is given the internal id will be returned.
Definition: gen.cpp:1310
double GetWidth() const
return width
Definition: canprim.h:147
double m_x2
control point
Definition: polyver.h:1025
Font info class, used as a single element for enumerating fonts.
Definition: stylebase.h:686
const a2dAffineMatrix & GetTransformMatrix() const
get the matrix used to position the object
Definition: canobj.h:500
void SetDescription(const wxString &desc)
Sets a description of the document.
Definition: candoc.h:430
a2dPoint2D GetStop() const
Get stop for gradient fill colour change.
Definition: stylebase.cpp:4733
const a2dFill * a2dINHERIT_FILL
global a2dFill stock object for INHERTED from parent object filling
Creates a shadow behind a a2dCanvasObject when added as property.
Definition: canprop.h:157
wxColour GetColour2() const
return colour 2
Definition: stylebase.cpp:4969
View on a a2dCanvasDocument.
Definition: candoc.h:212
void SetRadius(double radius)
set radius
Definition: canprim.h:578
double GetRadius() const
return radius
Definition: canprim.h:581
Cubic Bezier curve.
Definition: polyver.h:1045
polygon defined with list of points.
Definition: polygon.h:45
size_t GetCount()
Return the number of segments.
Definition: vpath.h:120
void SetTransformMatrix(const a2dAffineMatrix &mat=a2dIDENTITY_MATRIX)
Returns the matrix used to position the object.
Definition: canobj.h:509
bool Rotate(double angle)
Rotate clockwise by the given number of degrees:
Definition: afmatrix.cpp:432
double GetRadius() const
return radius
Definition: canprim.h:151
double wxDegToRad(double deg)
conversion from degrees to radians
Definition: artglob.cpp:30
wxOutputStream a2dDocumentOutputStream
output stream based wxStreams
Definition: gen.h:3458
double m_y2
control point
Definition: polyver.h:1027
double GetY2() const
Get Y2 of arc being end point of arc.
Definition: canprim.h:872
double m_y3
control point 2
Definition: polyver.h:1100
Arc Segment.
Definition: polyver.h:1112
double GetBase()
return how broad the basis of the arrow is.
Definition: canprim.h:246
bool IsIdentity(void) const
Is the matrix the identity matrix?
Definition: afmatrix.h:147
double m_x3
control point 2
Definition: polyver.h:1098
double GetRadius() const
Get stop for gradient fill colour change.
Definition: stylebase.cpp:4765
bool GetPixelStroke() const
if the width is pixels or not.
Definition: stylebase.cpp:6335
wxString A2DGENERALDLLEXP ColourToHex(const wxColour &colour)
RGB to 3-digit hex.
Definition: gen.cpp:5295
double GetValue(int col, int row) const
get the value in the matrix at col,row
Definition: afmatrix.cpp:106
bool IsNoFill() const
Definition: stylebase.h:273
wxUint32 GetStamp() const
time stamp gradient fill
Definition: stylebase.cpp:4739
a2dRectC is a centered rectangle
Definition: canprim.h:99
void SetFilename(const wxString filename, wxBitmapType type, bool doread=true)
set filename and type of image for saving.
Definition: canimage.cpp:249
bool SkewX(double degrees)
Skew Xaxis:
Definition: afmatrix.cpp:441
double GetWidth() const
return width
Definition: canprim.h:337
a2dCanvasObject * GetEnd()
dummies to be compatible with a2dEndsLine
Definition: canprim.h:1206
vertex array of line and arc segments.
Definition: polyver.h:494
a2dCanvasObject is the base class for Canvas Objects.
Definition: canobj.h:371
void SetFillRule(wxPolygonFillMode val)
Set Polygon filling mode wxODDEVEN_RULE or wxWINDING_RULE.
Definition: polygon.h:243
wxColour GetColour() const
return colour 1
Definition: stylebase.cpp:6131
a2dAffineMatrix a2dIDENTITY_MATRIX
global a2dAffineMatrix to set/pass the identity matrix.
Definition: afmatrix.cpp:51
double m_y2
control point 1
Definition: polyver.h:1095
property to hold a a2dObjectPtr smart pointer type variable to be associated with a a2dObject ...
Definition: gen.h:2199
Docview framework its controlling class.
a2dCanvasObjectArrayReference is an array of a reference to any a2dCanvasObject derived class...
Definition: recur.h:131
a2dPATHSEG_END GetClose() const
is this segment the closing a part since the last move
Definition: polyver.h:910
virtual a2dObject * GetRefObject() const
when a2dProperty, return its value else assert
Definition: gen.cpp:1976
void SetWidth(double w)
set width of rectangle
Definition: canprim.h:328
a2dPATHSEG m_type
easy way to test type of segment
Definition: polyver.h:928
a2dCanvasObjectList * GetChildObjectList()
get the list where the child objects are stored in.
Definition: canobj.cpp:2551
vertex list of line and arc segments.
Definition: polyver.h:600
bool ParseSvgStyle(a2dCanvasObject *parent)
Definition: parssvg.cpp:543
bool GetVisible()
is the layer visible
Definition: layerinf.cpp:341
double GetStart()
return start angle
Definition: canprim.h:733
a2dFont GetFont() const
get font for text
Definition: cantext.h:251
virtual a2dObject * GetRefObject() const
when a2dProperty, return its value else assert
Definition: canprop.cpp:321
void SetHeight(double h)
set height of rectangle
Definition: canprim.h:334
a2dText is an abstract base class.
Definition: cantext.h:93
a2dCanvasObjectList * wxNullCanvasObjectList
define a NON a2dCanvasObjectList
Definition: objlist.cpp:53
double GetWidth()
return width
Definition: canprim.h:53
double m_y2
second control point
Definition: polyver.h:1188
a2dOrigin stays at World Coordinate Zero (0,0) not matter what.
Definition: canprim.h:31
#define forEachIn(listtype, list)
easy iteration for a2dlist
Definition: a2dlist.h:111
a2dEllipse centered at x,y.
Definition: canprim.h:635
polyline defined with list of points.
Definition: polygon.h:332
double GetL2()
return Distance from top to the inside of the arrow.
Definition: canprim.h:243
const a2dError a2dError_XMLparse
a2dPoint2D GetStart() const
Get start for gradient fill colour change.
Definition: stylebase.cpp:4727
Normal straight line segment in a2dVpath.
Definition: polyver.h:878
#define wxStaticCast(obj, className)
The wxWindows 2.4.2 wxStaticCast is buggy. It evaluates its argument twice.
Definition: gen.h:123
a2dPoint2D GetCenter() const
Get start for gradient fill colour change.
Definition: stylebase.cpp:4753
a2dVertexListPtr GetSegments()
Get the list of points ( this is not a copy! )
Definition: polygon.h:219
a2dImage (will scale/rotate image when needed)
Definition: canimage.h:33
double wxRadToDeg(double rad)
conversion from radians to degrees
Definition: artglob.cpp:31
Normal straight line segment in a2dVertexList and a2dVertexArray.
Definition: polyver.h:163
virtual a2dPolygonL * GetClipObject() const
return a2dPolygonL that is used for clipping
Definition: canprop.h:337
double GetL1()
Returns the arrow length.
Definition: canprim.h:240
bool ParsePathPoints(a2dVpath *points)
Definition: parssvg.cpp:1105
a2dSLine
Definition: canprim.h:987
void CreateSVGSpline(const a2dVertexList *vertexList, bool asPolygon=false, const wxString &style=_T(""))
Generates a quadratic spline path in SVG from a set of points representing the control polygon...
Definition: parssvg.cpp:2088
void SetTextHeight(double height)
set text height in world coordinates
Definition: cantext.h:173
void Translate(double x, double y)
relative translate the object to position x,y in world coordinates
Definition: canobj.h:569
void DoSave(const a2dCanvasObject *object, int layer)
Generates SVG XML code for different types of canvas objects.
Definition: parssvg.cpp:2247
bool SkewY(double degrees)
Skew Yaxis:
Definition: afmatrix.cpp:460
wxUint16 GetLayer() const
Returns the layer index where this object is drawn upon.
Definition: canobj.h:2368
const a2dFill & GetFill() const
Definition: canprop.h:76
contains the layer properties for one layer,
Definition: layerinf.h:41
const a2dStroke * a2dINHERIT_STROKE
global a2dStroke stock object for INHERTED from parent object stroking
double GetTextHeight() const
get text height in world coordinates
Definition: cantext.h:176
bool CanSave(const wxObject *obj=NULL)
Should return true if the handler can write this document to a stream.
Definition: parssvg.cpp:1536
a2dPoint2D GetFocal() const
Get start for gradient fill colour change.
Definition: stylebase.cpp:4759
const a2dFill * a2dNullFILL
global a2dFill stock object for defining NO filling
WX_DECLARE_STRING_HASH_MAP(a2dPropertyId *, a2dPropertyIdHashMap)
Declaration of the hash map type to convert prop names to prop id objects.
double GetPosY2(bool transform=true) const
Get (transformed) position of Y2.
Definition: canprim.cpp:3875
bool GetSpline()
Get the polygon spline setting.
Definition: polygon.h:235
bool Identity(void)
Make into identity matrix.
Definition: afmatrix.cpp:256
a2dArrow is used for having line begin and ends on specific objects.
Definition: canprim.h:198
void SetWidth(double width)
set width
Definition: canimage.h:118
double GetX1() const
Get X1 of arc being begin point of arc.
Definition: canprim.h:866
double m_x2
control point 1
Definition: polyver.h:1093
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
a2dView * GetCurrentView() const
return the one that is active right now (e.g. has focus in case of a wxWindow), or NULL ...
Definition: doccom.cpp:1185
const a2dStroke * a2dNullSTROKE
global a2dStroke stock object for NO stroking
wxString & GetFilename()
get filename
Definition: canimage.h:131
double GetPosX1(bool transform=true) const
Get (transformed) position of X1.
Definition: canprim.cpp:3845
virtual a2dLineSegment * Clone()
create exact copy
Definition: polyver.cpp:250
while iterating a a2dCanvasDocument, this holds the context.
Definition: canobj.h:3212
wxInputStream a2dDocumentInputStream
input stream based wxStreams
Definition: gen.h:3456
double m_x
x endpoint of line
Definition: polyver.h:232
virtual bool CanLoad(a2dDocumentInputStream &stream, const wxObject *obj=NULL, wxClassInfo *docClassInfo=NULL)
Should return true if the handler can read from the stream.
Definition: parssvg.cpp:58
double m_y
y endpoint of line
Definition: polyver.h:235
a2dDocviewGlobal * a2dDocviewGlobals
a global pointer to get to global instance of important classes.
Definition: doccom.cpp:2348
void SetStroke(const wxColour &strokecolor, double width=0, a2dStrokeStyle style=a2dSTROKE_SOLID)
Set a stroke for the object which will be used instead of the layer stroke.
Definition: canobj.cpp:2924
double GetHeight() const
get height of image
Definition: canimage.h:114
std::vector< a2dLayerInfoPtr > & GetReverseOrderIndex()
return array index on ReverseOrder
Definition: layerinf.cpp:569
void SetHeight(double height)
set height
Definition: canimage.h:122
Clipping Path property that can be added to a2dCanvasObject&#39;s.
Definition: canprop.h:322
void SetText(const wxString &text)
set the text for the object &#39; &#39; in string means new line
Definition: cantext.h:165
Each a2dCanvasView needs to have a a2dCanvasDocument set in order to render data. ...
Definition: candoc.h:374
virtual bool Load(a2dDocumentInputStream &stream, wxObject *doc)
override to read the stream and store (part of) the contents in to a specific a2dDocument or othere o...
Definition: parssvg.cpp:87
double m_y1
y endpoint of line
Definition: polyver.h:922
a2dEndsLine with begin and/or end object.
Definition: canprim.h:1174
a2dCanvasObject * GetBegin()
dummies to be compatible with a2dEndsLine
Definition: canprim.h:1201
const wxString & GetStyle() const
Get style of font, e.g. Bold.
Definition: stylebase.h:722
return to contain children bbox
Definition: canobj.h:667
wxColour GetColour() const
return colour
Definition: stylebase.cpp:5012
bool Scale(double scale)
Scale by scale (isotropic scaling i.e. the same in x and y):
Definition: afmatrix.cpp:270
bool Translate(double x, double y)
Translate by dx, dy:
Definition: afmatrix.cpp:420
const a2dStroke & GetStroke() const
Definition: canprop.h:80
virtual void ReportErrorF(const a2dError &error, const wxChar *Format,...)
concatenate to the the error report the given error.
Definition: comevt.cpp:1312
const a2dStroke * a2dTRANSPARENT_STROKE
global a2dStroke stock object for TRANSPARENT stroking
double GetRadius() const
return radius
Definition: canprim.h:494
a2dDocumentCommandProcessor * GetDocviewCommandProcessor() const
Gets a2dDocumentCommandProcessor pointer.
Definition: doccom.h:1034
double GetEndScaleX()
scale begin and end object with this factor in X
Definition: polygon.h:389
a2dRect
Definition: canprim.h:440
const a2dNamedPropertyList & GetPropertyList() const
Get the Property List.
Definition: gen.h:1510
std::vector< a2dLayerInfoPtr > & GetOrderIndex()
return array index on Order
Definition: layerinf.cpp:562
void SetTitle(const wxString &title, bool notifyViews=false)
Sets the title for this document.
double GetX2() const
Get X2 of arc being end point of arc.
Definition: canprim.h:870
double GetEnd()
return end angle
Definition: canprim.h:743
void SetValue(int col, int row, double value)
set the value in the matrix at col,row
Definition: afmatrix.cpp:114
float GetWidth() const
Definition: stylebase.cpp:6281
a2dArc centered at x,y
Definition: canprim.h:823
double m_x1
x endpoint of line
Definition: polyver.h:919
virtual bool Save(a2dDocumentOutputStream &stream, const wxObject *doc)
Override to write to the stream and store (part of) of the document contents in the stream...
Definition: parssvg.cpp:1543
a2dVpath * GetSegments()
modify point at index to x,y
Definition: vpath.h:117
all headers of the canvas module
double GetY1() const
Get Y1 of arc being begin point of arc.
Definition: canprim.h:868
a2dCanvasObject for a Vector Path
Definition: vpath.h:55
int GetAlignment() const
Get the position of the anchor point w.r.t the text.
Definition: cantext.h:304
double GetPosY1(bool transform=true) const
Get (transformed) position of Y1.
Definition: canprim.cpp:3855
Vector Path.
Definition: polyver.h:1211
const a2dFontInfo & GetFontInfo() const
Get fontinfo of the font.
Definition: stylebase.cpp:2901
void SetRotation(double rotation)
set rotation
Definition: afmatrix.cpp:815
void Append(a2dCanvasObject *obj)
append a a2dCanvasObject to the childobjects
Definition: canobj.cpp:6224
double GetHeight() const
return height
Definition: canprim.h:339
wxString GetText() const
get the text of the object &#39; &#39; in string means new line
Definition: cantext.h:168
bool Start(a2dObject *object)
start removing properties from the object given, and down.
Definition: algos.h:634
double GetHeight() const
return height
Definition: canprim.h:149
double m_x2
second control point
Definition: polyver.h:1186
const double wxPI
defines PI
Definition: artglob.cpp:28
wxInt64 GetUniqueSerializationId() const
return a unique id for this object
Definition: gen.cpp:1450
void SetFill(const a2dFill &fill)
Set a fill for the object which will be used instead of the layer fill.
Definition: canobj.cpp:2874
a2dEllipticArc centered at x,y
Definition: canprim.h:697
double GetHeight()
return height
Definition: canprim.h:56
const a2dFill * a2dTRANSPARENT_FILL
global a2dFill stock object for TRANSPARENT filling
parssvg.cpp Source File -- Sun Oct 12 2014 17:04:23 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation