00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "a2dprec.h"
00013
00014 #ifdef __BORLANDC__
00015 #pragma hdrstop
00016 #endif
00017
00018 #ifndef WX_PRECOMP
00019 #include "wx/wx.h"
00020 #endif
00021
00022 #include "a2dprivate.h"
00023
00024
00025 #ifdef _MSC_VER
00026 #pragma warning(disable: 4786)
00027 #endif
00028
00029 #include "wx/txtstrm.h"
00030 #include "wx/wfstream.h"
00031 #include "wx/intl.h"
00032 #include "wx/log.h"
00033 #include "wx/strconv.h"
00034 #include <wx/tokenzr.h>
00035
00036 #include "wx/canvas/canmod.h"
00037
00038 #include "wx/svgio/parssvg.h"
00039
00040
00041 using namespace std;
00042
00043
00044
00045
00046
00047 a2dIOHandlerSVGIn::a2dIOHandlerSVGIn()
00048 {
00049 m_fill = a2dFill();
00050 m_stroke = *a2dNullSTROKE;
00051 m_docClassInfo = &a2dCanvasDocument::ms_classInfo;
00052 }
00053
00054 a2dIOHandlerSVGIn::~a2dIOHandlerSVGIn()
00055 {
00056 }
00057
00058 bool a2dIOHandlerSVGIn::CanLoad( a2dDocumentInputStream& stream, const wxObject* obj, wxClassInfo* docClassInfo )
00059 {
00060 if ( obj && !wxDynamicCast( obj, a2dCanvasDocument) )
00061 return false;
00062
00063 if ( docClassInfo && m_docClassInfo && !docClassInfo->IsKindOf( m_docClassInfo ) )
00064 return false;
00065
00066 m_streami = &stream;
00067 SeekI( 0 );
00068
00069 wxString header;
00070 char buf[1000];
00071 int last_read = Read( buf, 1000);
00072
00073 if(last_read > 1000){
00074 last_read = 1000;
00075 }
00076 header = wxString(buf, wxConvUTF8, last_read);
00077
00078 SeekI( 0 );
00079
00080 return ( header.Contains( _T("<?xml") ) && header.Contains(_T("<!DOCTYPE") ) && header.Contains(_T("<svg" ))
00081 ||
00082 header.Contains(_T("<svg") )
00083 );
00084 }
00085
00086 bool a2dIOHandlerSVGIn::Load( a2dDocumentInputStream& stream , wxObject* doc )
00087 {
00088 m_streami = &stream;
00089 m_doc = wxStaticCast( doc, a2dCanvasDocument);
00090
00091 InitializeLoad();
00092
00093 bool oke;
00094
00095 try
00096 {
00097 oke = LoadSvg( m_doc );
00098 }
00099 catch (const a2dIOHandlerXMLException& e)
00100 {
00101 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("%s at line %d column %d"), e.getMessage().c_str(), e.getLineNumber(), e.getColumnNumber());
00102 oke = false;
00103 }
00104
00105 ResetLoad();
00106
00107 return oke;
00108 }
00109
00110 #ifdef new
00111 #undef new
00112 #endif
00113
00114 #include <wx/hashmap.h>
00115
00116 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS && wxUSE_DEBUG_NEW_ALWAYS
00117 #define new new(__TFILE__,__LINE__)
00118 #endif
00119
00120 WX_DECLARE_STRING_HASH_MAP( wxString, StringStringHashMap);
00121 static StringStringHashMap m_shapeclass;
00122 static wxString m_defaultclass;
00123 static double m_defaultfontsize;
00124
00125 bool a2dIOHandlerSVGIn::LoadSvg( a2dCanvasDocument* doc )
00126 {
00127 Next();
00128 Require( START_TAG, _T("svg") );
00129
00130 m_defaultclass = GetAttributeValue( _T("class") );
00131
00132 Next();
00133 if ( GetTagName() == _T("title") )
00134 {
00135 doc->SetTitle(GetContent());
00136 Next();
00137 Require( END_TAG, _T("title") );
00138 Next();
00139 }
00140 if ( GetTagName() == _T("desc") )
00141 {
00142 doc->SetDescription(GetContent());
00143 Next();
00144 Require( END_TAG, _T("desc") );
00145 Next();
00146 }
00147
00148 a2dFill fill = m_fill;
00149 a2dStroke stroke = m_stroke;
00150 m_doc->GetRootObject()->SetFill( fill );
00151 m_doc->GetRootObject()->SetStroke( stroke );
00152
00153 if ( GetEventType() == START_TAG && GetTagName() == _T("g") )
00154 {
00155 do
00156 {
00157 LoadSvgGroup( m_doc->GetRootObject() );
00158 m_fill = m_doc->GetRootObject()->GetFill();
00159 m_stroke = m_doc->GetRootObject()->GetStroke();
00160 }
00161 while( GetTagName() != _T("svg") );
00162 }
00163 else
00164 {
00165 do
00166 {
00167 LoadSvgGroupElement( m_doc->GetRootObject() );
00168 }
00169 while( GetTagName() != _T("svg") );
00170 }
00171 return true;
00172 }
00173
00174 bool a2dIOHandlerSVGIn::LoadSvgGroupElement( a2dCanvasObject* g )
00175 {
00176 if ( GetEventType() != START_TAG )
00177 return false;
00178
00179 wxString elementname = GetTagName();
00180 if (
00181 elementname != _T("g") &&
00182 elementname != _T("a") &&
00183 elementname != _T("rect") &&
00184 elementname != _T("text") &&
00185 elementname != _T("circle") &&
00186 elementname != _T("ellipse") &&
00187 elementname != _T("polygon") &&
00188 elementname != _T("polyline") &&
00189 elementname != _T("line") &&
00190 elementname != _T("path") &&
00191 elementname != _T("image")
00192 )
00193 {
00194 if( elementname == _T("style") && g == m_doc->GetRootObject() )
00195 {
00196 wxString style = GetContent();
00197
00198 style.Trim();
00199 wxStringTokenizer tkz( style, _T("{}") );
00200 while ( tkz.HasMoreTokens() )
00201 {
00202 wxString shapeclass = tkz.GetNextToken().Trim(false).Trim();
00203 wxString shapestyle = tkz.GetNextToken().Trim(false).Trim();
00204 if ( shapeclass.Length()>1 && shapestyle.IsEmpty () == false && shapeclass[(size_t)0] == _T('.') )
00205 {
00206 shapeclass = shapeclass.Right( shapeclass.Length()-1 );
00207 m_shapeclass[shapeclass] = shapestyle ;
00208 }
00209 }
00210
00211 if( m_defaultclass != _T("") )
00212 {
00213 wxString defaultstyle = m_shapeclass[m_defaultclass];
00214 if( defaultstyle.Find( _T("font-size:") ) >= 0 )
00215 {
00216 defaultstyle = defaultstyle.Right( defaultstyle.Length() - defaultstyle.Find( _T("font-size:") ) - wxString( _T("font-size:") ).Length() );
00217 defaultstyle.ToDouble( &m_defaultfontsize );
00218 }
00219 }
00220
00221 SkipSubTree();
00222 Require( END_TAG, elementname );
00223 Next();
00224 return true;
00225 }
00226 else
00227 {
00228
00229 wxString parseerror = _T("not implemented or unknown element ") + GetTagName();
00230 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: '%s' at line %d"), parseerror.c_str(), GetCurrentLineNumber() );
00231 SkipSubTree();
00232 Require( END_TAG, elementname );
00233 Next();
00234 return true;
00235 }
00236 }
00237
00238 if ( LoadSvgGroup( g ) ||
00239 LoadSvgAnchor( g ) ||
00240 LoadSvgRect( g ) ||
00241 LoadSvgText( g ) ||
00242 LoadSvgCircle( g ) ||
00243 LoadSvgEllipse( g ) ||
00244 LoadSvgPolygon( g ) ||
00245 LoadSvgPolyline( g ) ||
00246 LoadSvgLine( g ) ||
00247 LoadSvgPath( g ) ||
00248 LoadSvgImage( g )
00249 )
00250 {
00251 }
00252 else
00253 {
00254 wxString parseerror = _T("not implemented or unknown element ") + GetTagName();
00255 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: '%s' at line %d"), parseerror.c_str(), GetCurrentLineNumber() );
00256
00257 }
00258
00259 return true;
00260 }
00261
00262 bool a2dIOHandlerSVGIn::LoadSvgGroup( a2dCanvasObject* parent )
00263 {
00264 if ( GetTagName() != _T("g") )
00265 return false;
00266
00267 a2dCanvasObject* g = new a2dCanvasObject();
00268 m_currentobject = g;
00269 parent->Append( m_currentobject );
00270
00271 ParseSvgTransForm( m_currentobject );
00272 ParseSvgStyle( m_currentobject );
00273
00274 Next();
00275
00276 while( 1 )
00277 {
00278 if (!LoadSvgGroupElement( g ) )
00279 {
00280 Require( END_TAG, _T("g") );
00281 Next();
00282 break;
00283 }
00284 else
00285 {
00286 m_fill = g->GetFill();
00287 m_stroke = g->GetStroke();
00288 }
00289 }
00290
00291 m_currentobject = g;
00292 m_fill = g->GetFill();
00293 m_stroke = g->GetStroke();
00294 return true;
00295 }
00296
00297 bool a2dIOHandlerSVGIn::LoadSvgAnchor( a2dCanvasObject* parent )
00298 {
00299 if ( GetTagName() != _T("a") )
00300 return false;
00301
00302 a2dCanvasObject* g = new a2dCanvasObject();
00303 m_currentobject = g;
00304 parent->Append( m_currentobject );
00305
00306 ParseSvgTransForm( m_currentobject );
00307 ParseSvgStyle( m_currentobject );
00308 ParseSvgLink( m_currentobject );
00309
00310 Next();
00311
00312 while( 1 )
00313 {
00314 if (!LoadSvgGroupElement( g ) )
00315 {
00316 Require( END_TAG, _T("a") );
00317 Next();
00318 break;
00319 }
00320 else
00321 {
00322 m_fill = g->GetFill();
00323 m_stroke = g->GetStroke();
00324 }
00325 }
00326
00327 m_currentobject = g;
00328 m_fill = g->GetFill();
00329 m_stroke = g->GetStroke();
00330
00331 return true;
00332 }
00333
00334 bool a2dIOHandlerSVGIn::ParseSvgTransForm( a2dCanvasObject* parent )
00335 {
00336 wxString str = GetAttributeValue( _T("transform") );
00337
00338 if ( str == _T("") )
00339 return false;
00340
00341 wxString numstr;
00342 double matrixcoef[6];
00343 int nr_matrixcoef;
00344
00345 wxString keywstr;
00346 size_t i;
00347
00348
00349 a2dAffineMatrix matrixtotal;
00350 matrixtotal.Identity();
00351 a2dAffineMatrix matrix;
00352
00353 for ( i =0; i < str.Len(); i++)
00354 {
00355
00356 while ( wxIsspace(str[i])) i++;
00357
00358 nr_matrixcoef = 0;
00359 keywstr.Clear();
00360
00361 while ( i < str.Len() && wxIsalpha (str[i]) )
00362 {
00363 keywstr += str.GetChar(i);
00364 i++;
00365 }
00366
00367
00368 while ( wxIsspace(str[i])) i++;
00369
00370 if ( str[i] != _T('(') )
00371 {
00372 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: missing ( at line %d"), GetCurrentLineNumber());
00373 return true;
00374 }
00375 i++;
00376
00377 while ( wxIsspace(str[i])) i++;
00378
00379 while ( i < str.Len() && str[i] != _T(')') )
00380 {
00381 numstr.Clear();
00382 while ( i < str.Len() && (wxIsdigit(str[i]) || str[i] == _T('+') || str[i] == _T('-') || str[i] == _T('.') || str[i] == _T('E') ) )
00383 {
00384 numstr += str.GetChar(i);
00385 i++;
00386 }
00387 numstr.ToDouble( &matrixcoef[nr_matrixcoef] );
00388 nr_matrixcoef++;
00389 while ( i < str.Len() && (wxIsspace(str[i]) || str[i] == _T(',')) ) i++;
00390 }
00391
00392 if ( str[i] != _T(')') )
00393 {
00394 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: missing ) at line %d"), GetCurrentLineNumber());
00395 return true;
00396 }
00397 i++;
00398
00399 if ( keywstr == _T("matrix") )
00400 {
00401 if (nr_matrixcoef != 6)
00402 {
00403 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00404 keywstr.c_str(),
00405 GetCurrentLineNumber());
00406 return true;
00407 }
00408 matrix.SetValue(0,0, matrixcoef[0] );
00409 matrix.SetValue(0,1, matrixcoef[1] );
00410 matrix.SetValue(1,0, matrixcoef[2] );
00411 matrix.SetValue(1,1, matrixcoef[3] );
00412 matrix.SetValue(2,0, matrixcoef[4] );
00413 matrix.SetValue(2,1, matrixcoef[5] );
00414
00415 matrixtotal = matrixtotal * matrix;
00416 }
00417 else if ( keywstr == _T("translate") )
00418 {
00419 if (nr_matrixcoef == 1)
00420 matrixcoef[0] = 0;
00421 else if (nr_matrixcoef != 2)
00422 {
00423 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00424 keywstr.c_str(),
00425 GetCurrentLineNumber());
00426 return true;
00427 }
00428
00429 matrix.Identity();
00430 matrix.Translate( matrixcoef[0] , matrixcoef[1] );
00431 matrix = a2dAffineMatrix( matrixcoef[0] , matrixcoef[1] );
00432 matrixtotal = matrixtotal * matrix;
00433 }
00434 else if ( keywstr == _T("scale") )
00435 {
00436 if (nr_matrixcoef == 1)
00437 matrixcoef[1] = matrixcoef[0];
00438 else if (nr_matrixcoef != 2)
00439 {
00440 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00441 keywstr.c_str(),
00442 GetCurrentLineNumber());
00443 return true;
00444 }
00445
00446 matrix.Identity();
00447 matrix.Scale( matrixcoef[0] , matrixcoef[1], 0, 0 );
00448 matrix = a2dAffineMatrix( 0, 0, matrixcoef[0] , matrixcoef[1] );
00449
00450 matrixtotal = matrixtotal * matrix;
00451 }
00452 else if ( keywstr == _T("rotate") )
00453 {
00454 if (nr_matrixcoef != 1)
00455 {
00456 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00457 keywstr.c_str(),
00458 GetCurrentLineNumber());
00459 return true;
00460 }
00461
00462 matrix.Identity();
00463 matrix.SetRotation( matrixcoef[0] );
00464 matrix = a2dAffineMatrix( 0, 0, 1, 1, -matrixcoef[0] );
00465 matrixtotal = matrixtotal * matrix;
00466 }
00467 else if ( keywstr == _T("skewX") )
00468 {
00469 if (nr_matrixcoef != 1)
00470 {
00471 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00472 keywstr.c_str(),
00473 GetCurrentLineNumber());
00474 return true;
00475 }
00476
00477 matrix.Identity();
00478 matrix.SkewX( matrixcoef[0] );
00479 matrixtotal = matrixtotal * matrix;
00480 }
00481 else if ( keywstr == _T("skewY") )
00482 {
00483 if (nr_matrixcoef != 1)
00484 {
00485 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00486 keywstr.c_str(),
00487 GetCurrentLineNumber());
00488 return true;
00489 }
00490
00491 matrix.Identity();
00492 matrix.SkewY( matrixcoef[0] );
00493 matrixtotal = matrixtotal * matrix;
00494 }
00495 else if ( keywstr == _T("flipX") )
00496 {
00497 if (nr_matrixcoef != 0)
00498 {
00499 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00500 keywstr.c_str(),
00501 GetCurrentLineNumber());
00502 return true;
00503 }
00504
00505 matrix.Identity();
00506 matrix.Mirror( true, false );
00507 matrixtotal = matrixtotal * matrix;
00508 }
00509 else if ( keywstr == _T("flipY") )
00510 {
00511 if (nr_matrixcoef != 0)
00512 {
00513 wxLogWarning(_("SVG : wrong number of arguments %s at line %d"),
00514 keywstr.c_str(),
00515 GetCurrentLineNumber());
00516 return true;
00517 }
00518
00519 matrix.Identity();
00520 matrix.Mirror( false, true );
00521 matrixtotal = matrixtotal * matrix;
00522 }
00523 else
00524 {
00525 wxLogWarning(_("SVG : invalid transform %s at line %d"),
00526 keywstr.c_str(),
00527 GetCurrentLineNumber());
00528 return true;
00529 }
00530 }
00531
00532 parent->SetTransformMatrix( matrixtotal );
00533 return true;
00534 }
00535
00536 bool a2dIOHandlerSVGIn::ParseSvgStyle( a2dCanvasObject* parent )
00537 {
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548 wxString styleattrib = GetAttributeValue( _T("style") ).Trim(false).Trim();
00549
00550
00551 if ( styleattrib == _T("") )
00552 {
00553 wxString classname = GetAttributeValue( _T("class") );
00554 if ( classname != _T("") )
00555 {
00556
00557 wxStringTokenizer tkz( classname, _T(" "));
00558 while ( tkz.HasMoreTokens() )
00559 {
00560 wxString oneitem = tkz.GetNextToken();
00561
00562 if( !m_shapeclass[oneitem].IsEmpty() )
00563 {
00564 if ( styleattrib.IsEmpty() )
00565 styleattrib = m_shapeclass[oneitem] ;
00566 else
00567 styleattrib = styleattrib + wxT(";") + m_shapeclass[oneitem] ;
00568 }
00569 }
00570 }
00571 }
00572 if ( styleattrib == _T("") )
00573 {
00574 parent->SetFill( *a2dINHERIT_FILL );
00575 parent->SetStroke( *a2dINHERIT_STROKE );
00576 return false;
00577 }
00578
00579 wxStringTokenizer tkz( styleattrib, _T(";"));
00580 while ( tkz.HasMoreTokens() )
00581 {
00582 wxStringTokenizer stylepart( tkz.GetNextToken(), _T(":") );
00583 wxString substyle = stylepart.GetNextToken().Trim(false).Trim();
00584 wxString value = stylepart.GetNextToken().Trim(false).Trim();
00585 double adouble;
00586 long aint;
00587 value.ToDouble( &adouble );
00588 value.ToLong( &aint );
00589 if ( substyle == _T("fill") )
00590 {
00591 if ( value != _T("none") )
00592 {
00593 m_fill = a2dFill( ParseSvgColour( value ));
00594 }
00595 else
00596 {
00597 m_fill = *a2dNullFILL;
00598 }
00599 }
00600 else if ( substyle == _T("fill-rule") )
00601 {
00602 if (0 != wxDynamicCast( parent, a2dPolygonL ))
00603 {
00604 a2dPolygonL* obj = wxDynamicCast( parent, a2dPolygonL );
00605
00606 if ( value == _T("evenodd") )
00607 obj->SetFillRule( wxODDEVEN_RULE );
00608 else if ( value == _T("nonzero") )
00609 obj->SetFillRule( wxWINDING_RULE );
00610 else
00611 wxLogWarning(_("SVG unknown style fill-rule: %s at line %d"),
00612 value.c_str(),
00613 GetCurrentLineNumber());
00614 }
00615 }
00616 else if ( substyle == _T("stroke") )
00617 {
00618 if ( value != _T("none") )
00619 {
00620 m_stroke = a2dStroke( ParseSvgColour( value ), a2dSTROKE_SOLID );
00621 }
00622 else
00623 {
00624 m_stroke = *a2dNullSTROKE;
00625 }
00626 }
00627 else if ( substyle == _T("opacity") )
00628 {
00629 m_fill.SetAlpha( aint );
00630 m_stroke.SetAlpha( aint );
00631 }
00632 else if ( substyle == _T("fill-opacity") )
00633 {
00634 m_fill.SetAlpha( aint);
00635 }
00636 else if ( substyle == _T("stroke-opacity") )
00637 {
00638 m_stroke.SetAlpha( aint );
00639 }
00640 else if ( substyle == _T("stroke-width") )
00641 {
00642 m_stroke.SetWidth( adouble );
00643 }
00644 else if ( substyle == _T("stroke-linecap") )
00645 {
00646 if ( value == _T("butt") )
00647 m_stroke.SetCap( wxCAP_BUTT );
00648 else if ( value == _T("round") )
00649 m_stroke.SetCap( wxCAP_ROUND );
00650 else if ( value == _T("square") )
00651 m_stroke.SetCap( wxCAP_PROJECTING );
00652 else
00653 wxLogWarning(_("SVG unknown line cap style: %s at line %d"),
00654 value.c_str(),
00655 GetCurrentLineNumber());
00656 }
00657 else if ( substyle == _T("stroke-linejoin") )
00658 {
00659 if ( value == _T("miter") )
00660 m_stroke.SetJoin( wxJOIN_MITER );
00661 else if ( value == _T("round") )
00662 m_stroke.SetJoin( wxJOIN_ROUND );
00663 else if ( value == _T("bevel") )
00664 m_stroke.SetJoin( wxJOIN_BEVEL );
00665 else
00666 wxLogWarning(_("SVG unknown line join style: %s at line %d"),
00667 value.c_str(),
00668 GetCurrentLineNumber());
00669 }
00670 else if ( substyle == _T("font-size") )
00671 {
00672
00673
00674
00675
00676 a2dText* obj = wxDynamicCast( parent, a2dText );
00677 if( obj )
00678 {
00679 if( value.Right(2) == _T("em") )
00680 {
00681 if( m_defaultfontsize < 0.1 )
00682 obj->SetTextHeight( 7 );
00683 else
00684 obj->SetTextHeight( m_defaultfontsize * adouble );
00685 }
00686 else
00687 obj->SetTextHeight( adouble );
00688 }
00689 }
00690 else if ( substyle == _T("font-family") )
00691 {
00692
00693
00694
00695
00696 }
00697 else if ( substyle == _T("stroke-miterlimit") )
00698 {
00699
00700
00701
00702
00703 }
00704 else
00705 wxLogWarning(_("SVG unknown style: %s: %s at line %d"),
00706 substyle.c_str(), value.c_str(),
00707 GetCurrentLineNumber());
00708 }
00709
00710 a2dFill fill = m_fill;
00711 a2dStroke stroke = m_stroke;
00712
00713 parent->SetFill( fill );
00714 parent->SetStroke( stroke );
00715
00716 return true;
00717 }
00718
00719 bool a2dIOHandlerSVGIn::ParseSvgLink( a2dCanvasObject* object)
00720 {
00721 wxString linkattrib = GetAttributeValue( _T("xlink:href") ).Trim(false).Trim();
00722 wxStringTokenizer tkz( linkattrib, _T(";"));
00723 while ( tkz.HasMoreTokens() )
00724 {
00725 wxString url = tkz.GetNextToken();
00726 object->SetURL( url );
00727 }
00728
00729 return true;
00730 }
00731
00732 bool a2dIOHandlerSVGIn::LoadSvgRect( a2dCanvasObject* parent )
00733 {
00734 if ( GetTagName() != _T("rect") )
00735 return false;
00736
00737 a2dRect* rect = new a2dRect();
00738 m_currentobject = rect;
00739 parent->Append( m_currentobject );
00740
00741 ParseSvgTransForm( m_currentobject );
00742 ParseSvgStyle( m_currentobject );
00743
00744 a2dAffineMatrix matrixtotal = rect->GetTransformMatrix();
00745 a2dAffineMatrix matrix;
00746 matrix.Identity();
00747 matrix.Translate( GetAttributeValueDouble( _T("x") ) , GetAttributeValueDouble( _T("y") ) );
00748 matrixtotal = matrixtotal * matrix;
00749 rect->SetTransformMatrix( matrixtotal );
00750
00751 rect->SetWidth( GetAttributeValueDouble( _T("width") ) );
00752 rect->SetHeight( GetAttributeValueDouble( _T("height") ) );
00753
00754 Next();
00755 Require( END_TAG, _T("rect") );
00756 Next();
00757
00758 return true;
00759 }
00760
00761 bool a2dIOHandlerSVGIn::LoadSvgCircle( a2dCanvasObject* parent )
00762 {
00763 if ( GetTagName() != _T("circle") )
00764 return false;
00765
00766 a2dCircle* circle = new a2dCircle();
00767 m_currentobject = circle;
00768 parent->Append( m_currentobject );
00769
00770 ParseSvgTransForm( m_currentobject );
00771 ParseSvgStyle( m_currentobject );
00772
00773 a2dAffineMatrix matrixtotal = circle->GetTransformMatrix();
00774 a2dAffineMatrix matrix;
00775 matrix.Identity();
00776 matrix.Translate( GetAttributeValueDouble( _T("cx") ) , GetAttributeValueDouble( _T("cy") ) );
00777 matrixtotal = matrixtotal * matrix;
00778 circle->SetTransformMatrix( matrixtotal );
00779
00780 circle->SetRadius( GetAttributeValueDouble( _T("r") ) );
00781
00782 Next();
00783 Require( END_TAG, _T("circle") );
00784 Next();
00785
00786 return true;
00787 }
00788
00789 bool a2dIOHandlerSVGIn::LoadSvgEllipse( a2dCanvasObject* parent )
00790 {
00791 if ( GetTagName() != _T("ellipse") )
00792 return false;
00793
00794 a2dEllipse* Ellipse = new a2dEllipse();
00795 m_currentobject = Ellipse;
00796 parent->Append( m_currentobject );
00797
00798 ParseSvgTransForm( m_currentobject );
00799 ParseSvgStyle( m_currentobject );
00800
00801 a2dAffineMatrix matrixtotal = Ellipse->GetTransformMatrix();
00802 a2dAffineMatrix matrix;
00803 matrix.Identity();
00804 matrix.Translate( GetAttributeValueDouble( _T("cx") ) , GetAttributeValueDouble( _T("cy") ) );
00805 matrixtotal = matrixtotal * matrix;
00806 Ellipse->SetTransformMatrix( matrixtotal );
00807
00808 Ellipse->SetWidth( GetAttributeValueDouble( _T("rx") )*2 );
00809 Ellipse->SetHeight( GetAttributeValueDouble( _T("ry") )*2 );
00810
00811 Next();
00812 Require( END_TAG, _T("ellipse") );
00813 Next();
00814
00815 return true;
00816 }
00817
00818 bool a2dIOHandlerSVGIn::LoadSvgText( a2dCanvasObject* parent )
00819 {
00820 if ( GetTagName() != _T("text") )
00821 return false;
00822
00823 a2dText* text = new a2dText(GetContent());
00824 m_currentobject = text;
00825 parent->Append( m_currentobject );
00826
00827 ParseSvgTransForm( m_currentobject );
00828 ParseSvgStyle( m_currentobject );
00829
00830 text->SetFill( *a2dTRANSPARENT_FILL );
00831
00832 a2dAffineMatrix matrixtotal = text->GetTransformMatrix();
00833 a2dAffineMatrix matrix;
00834 matrix.Identity();
00835 matrix.Translate( GetAttributeValueDouble( _T("x") ) , GetAttributeValueDouble( _T("y") ) );
00836 matrixtotal = matrixtotal * matrix;
00837 text->SetTransformMatrix( matrixtotal );
00838
00839 Next();
00840
00841 if( GetEventType() == END_TAG )
00842 {
00843 Require( END_TAG, _T("text") );
00844 Next();
00845 }
00846 else
00847 {
00848 wxString s = _T("");
00849 while( GetEventType() != END_TAG || GetTagName() != _T("text") )
00850 {
00851 if( !GetContent().IsEmpty() )
00852 {
00853 s = s + GetContent();
00854 }
00855 Next();
00856 }
00857 text->SetText( s );
00858 Next();
00859 }
00860
00861
00862 return true;
00863 }
00864
00865 bool a2dIOHandlerSVGIn::ParsePoints( a2dVertexList* points )
00866 {
00867 wxString pstr = GetAttributeValue( _T("points") );
00868
00869 if ( pstr == _T("") )
00870 return false;
00871
00872 wxString numstr;
00873
00874 int j=0;
00875 double x = 0.0, y = 0.0;
00876 size_t i;
00877
00878 for ( i =0; i < pstr.Len(); i++)
00879 {
00880 if ( pstr[i] != _T(' ') && pstr[i] != _T(','))
00881 {
00882 if ( j == 0 )
00883 { numstr.Clear();
00884 while ( i < pstr.Len() && pstr[i] != _T(' ') && pstr[i] != _T(',') )
00885 {
00886 numstr += pstr.GetChar(i);
00887 i++;
00888 }
00889 numstr.ToDouble( &x );
00890 j++;
00891 }
00892 else
00893 { numstr= _T("");
00894 while ( i < pstr.Len() && pstr[i] != _T(' ') && pstr[i] != _T(',') )
00895 {
00896 numstr += pstr.GetChar(i);
00897 i++;
00898 }
00899 numstr.ToDouble( &y );
00900 j--;
00901 points->push_back( new a2dLineSegment( x, y ) );
00902 }
00903 }
00904 }
00905 return true;
00906 }
00907
00908 bool a2dIOHandlerSVGIn::LoadSvgPolygon( a2dCanvasObject* parent )
00909 {
00910 if ( GetTagName() != _T("polygon") )
00911 return false;
00912
00913 a2dVertexList* points = new a2dVertexList();
00914
00915 if (!ParsePoints( points ))
00916 {
00917 delete points;
00918 wxString parseerror = _T("points missing in polygon");
00919 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: '%s' at line %d"), parseerror.c_str(), GetCurrentLineNumber() );
00920 return true;
00921 }
00922
00923 a2dPolygonL* poly = new a2dPolygonL( points );
00924 m_currentobject = poly;
00925 parent->Append( m_currentobject );
00926
00927 ParseSvgTransForm( m_currentobject );
00928 ParseSvgStyle( m_currentobject );
00929
00930 Next();
00931 Require( END_TAG, _T("polygon") );
00932 Next();
00933
00934 return true;
00935 }
00936
00937 bool a2dIOHandlerSVGIn::LoadSvgPolyline( a2dCanvasObject* parent )
00938 {
00939 if ( GetTagName() != _T("polyline") )
00940 return false;
00941
00942 a2dVertexList* points = new a2dVertexList();
00943
00944 if (!ParsePoints( points ))
00945 {
00946 delete points;
00947 wxString parseerror = _T("points missing in polyline");
00948 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: '%s' at line %d"),
00949 parseerror.c_str(),
00950 GetCurrentLineNumber() );
00951 return true;
00952 }
00953
00954 a2dPolylineL* poly = new a2dPolylineL( points );
00955 m_currentobject = poly;
00956 parent->Append( m_currentobject );
00957
00958 ParseSvgTransForm( m_currentobject );
00959 ParseSvgStyle( m_currentobject );
00960
00961 Next();
00962 Require( END_TAG, _T("polyline") );
00963 Next();
00964
00965 return true;
00966 }
00967
00968 bool a2dIOHandlerSVGIn::LoadSvgLine( a2dCanvasObject* parent )
00969 {
00970 if ( GetTagName() != _T("line") )
00971 return false;
00972
00973 double x1 = GetAttributeValueDouble( _T("x1") );
00974 double y1 = GetAttributeValueDouble( _T("y1") );
00975 double x2 = GetAttributeValueDouble( _T("x2") );
00976 double y2 = GetAttributeValueDouble( _T("y2") );
00977
00978 a2dSLine* line = new a2dSLine( x1, y1, x2, y2 );
00979
00980 m_currentobject = line;
00981 parent->Append( m_currentobject );
00982
00983 ParseSvgTransForm( m_currentobject );
00984 ParseSvgStyle( m_currentobject );
00985
00986 Next();
00987 Require( END_TAG, _T("line") );
00988 Next();
00989
00990 return true;
00991 }
00992
00993
00994 #ifndef M_PI
00995 #define M_PI (3.1415926535897932384626433832795028841972)
00996 #endif
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023 static void
01024 rsvg_path_arc (double startx, double starty,
01025 double rx, double ry, double x_axis_rotation,
01026 int large_arc_flag, int sweep_flag,
01027 double x, double y,
01028 double* pcx, double* pcy,
01029 double* pangle)
01030 {
01031 double sin_th, cos_th;
01032 double a00, a01, a10, a11;
01033 double x0, y0, x1, y1, xc, yc;
01034 double d, sfactor, sfactor_sq;
01035 double th0, th1, th_arc;
01036 int n_segs;
01037
01038 sin_th = sin (x_axis_rotation * (M_PI / 180.0));
01039 cos_th = cos (x_axis_rotation * (M_PI / 180.0));
01040 a00 = cos_th / rx;
01041 a01 = sin_th / rx;
01042 a10 = -sin_th / ry;
01043 a11 = cos_th / ry;
01044 x0 = a00 * startx + a01 * starty;
01045 y0 = a10 * startx + a11 * starty;
01046 x1 = a00 * x + a01 * y;
01047 y1 = a10 * x + a11 * y;
01048
01049
01050
01051
01052
01053 d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
01054 sfactor_sq = 1.0 / d - 0.25;
01055 if (sfactor_sq < 0) sfactor_sq = 0;
01056 sfactor = sqrt (sfactor_sq);
01057 if (sweep_flag == large_arc_flag) sfactor = -sfactor;
01058 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
01059 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
01060
01061
01062 th0 = atan2 (y0 - yc, x0 - xc);
01063 th1 = atan2 (y1 - yc, x1 - xc);
01064
01065 th_arc = th1 - th0;
01066 if (th_arc < 0 && sweep_flag)
01067 th_arc += 2 * M_PI;
01068 else if (th_arc > 0 && !sweep_flag)
01069 th_arc -= 2 * M_PI;
01070
01071 n_segs = (int) ceil (fabs (th_arc / (M_PI * 0.5 + 0.001)));
01072
01073
01074 sin_th = sin (x_axis_rotation * (M_PI / 180.0));
01075 cos_th = cos (x_axis_rotation * (M_PI / 180.0));
01076
01077 a00 = cos_th * rx;
01078 a01 = -sin_th * ry;
01079 a10 = sin_th * rx;
01080 a11 = cos_th * ry;
01081
01082 double th_half = 0.5 * (th1 - th0);
01083 double t = (8.0 / 3.0) * sin (th_half * 0.5) * sin (th_half * 0.5) / sin (th_half);
01084 x1 = xc + cos (th0) - t * sin (th0);
01085 y1 = yc + sin (th0) + t * cos (th0);
01086
01087
01088
01089
01090 *pcx = a00 * xc + a01 * yc;
01091 *pcy = a10 * xc + a11 * yc;
01092
01093 *pangle = th_arc;
01094 }
01095
01096 bool a2dIOHandlerSVGIn::ParsePathPoints( a2dVpath* points )
01097 {
01098 wxString buffer = GetAttributeValue( _T("d") );
01099
01100 if ( buffer == _T("") )
01101 return false;
01102
01103 unsigned int position = 0;
01104
01105 double lastmovex = 0;
01106 double lastmovey = 0;
01107 double lastx = 0;
01108 double lasty = 0;
01109
01110
01111 a2dVpathSegment* prev = 0;
01112 a2dVpathSegment* seg = 0;
01113
01114 char current;
01115
01116 SkipSpaces( buffer, position );
01117
01118 while ( position < buffer.Len() )
01119 {
01120 current = buffer[ position ];
01121 char command = current;
01122 position++;
01123 SkipSpaces( buffer, position );
01124 try
01125 {
01126 switch (current)
01127 {
01128 case _T('z'):
01129 case _T('Z'):
01130 {
01131 lastx = lastmovex;
01132 lasty = lastmovey;
01133 prev = seg;
01134 seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
01135 points->push_back( seg );
01136 break;
01137 }
01138 case _T('m'):
01139 case _T('M'):
01140 {
01141 if (command == _T('m'))
01142 lastx += ParseDouble( buffer, position );
01143 else
01144 lastx = ParseDouble( buffer, position );
01145
01146 SkipCommaSpaces( buffer, position );
01147
01148 if (command == _T('m'))
01149 lasty += ParseDouble( buffer, position );
01150 else
01151 lasty = ParseDouble( buffer, position );
01152
01153 SkipCommaSpaces( buffer, position );
01154
01155 prev = seg;
01156 seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_MOVETO );
01157 points->push_back( seg );
01158
01159 lastmovex = lastx;
01160 lastmovey = lasty;
01161 for (;;)
01162 {
01163 current = buffer[ position ];
01164 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01165 {
01166 if (command == _T('m'))
01167 lastx += ParseDouble( buffer, position );
01168 else
01169 lastx = ParseDouble( buffer, position );
01170
01171 SkipCommaSpaces( buffer, position );
01172
01173 if (command == _T('m'))
01174 lasty += ParseDouble( buffer, position );
01175 else
01176 lasty = ParseDouble( buffer, position );
01177
01178 prev = seg;
01179 seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
01180 points->push_back( seg );
01181 }
01182 else
01183 break;
01184 SkipCommaSpaces( buffer, position );
01185 }
01186 break;
01187 }
01188 case _T('l'):
01189 case _T('L'):
01190 {
01191 for (;;)
01192 {
01193 current = buffer[ position ];
01194 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01195 {
01196 if (command == _T('l'))
01197 lastx += ParseDouble( buffer, position );
01198 else
01199 lastx = ParseDouble( buffer, position );
01200
01201 SkipCommaSpaces( buffer, position );
01202
01203 if (command == _T('l'))
01204 lasty += ParseDouble( buffer, position );
01205 else
01206 lasty = ParseDouble( buffer, position );
01207
01208 prev = seg;
01209 seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
01210 points->push_back( seg );
01211 }
01212 else
01213 break;
01214 SkipCommaSpaces( buffer, position );
01215 }
01216 break;
01217 }
01218 case _T('h'):
01219 case _T('H'):
01220 {
01221 for (;;)
01222 {
01223 current = buffer[ position ];
01224 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01225 {
01226 if (command == _T('h'))
01227 lastx += ParseDouble( buffer, position );
01228 else
01229 lastx = ParseDouble( buffer, position );
01230
01231 prev = seg;
01232 seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
01233 points->push_back( seg );
01234 }
01235 else
01236 break;
01237 SkipCommaSpaces( buffer, position );
01238 }
01239 break;
01240 }
01241 case _T('V'):
01242 case _T('v'):
01243 {
01244 for (;;)
01245 {
01246 current = buffer[ position ];
01247 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01248 {
01249 if (command == _T('v'))
01250 lasty += ParseDouble( buffer, position );
01251 else
01252 lasty = ParseDouble( buffer, position );
01253
01254 prev = seg;
01255 seg = new a2dVpathSegment( lastx, lasty, a2dPATHSEG_LINETO );
01256 points->push_back( seg );
01257 }
01258 else
01259 break;
01260 SkipCommaSpaces( buffer, position );
01261 }
01262 break;
01263 }
01264 case _T('c'):
01265 case _T('C'):
01266 case _T('s'):
01267 case _T('S'):
01268 {
01269 double x1 = 0.0,y1 = 0.0,x2,y2,x,y;
01270 for (;;)
01271 {
01272 current = buffer[ position ];
01273 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01274 {
01275 if (command == _T('C') || command == _T('c'))
01276 {
01277 x1 = ParseDouble( buffer, position );
01278 SkipCommaSpaces( buffer, position );
01279 y1 = ParseDouble( buffer, position );
01280 SkipCommaSpaces( buffer, position );
01281 }
01282 x2 = ParseDouble( buffer, position );
01283 SkipCommaSpaces( buffer, position );
01284 y2 = ParseDouble( buffer, position );
01285 SkipCommaSpaces( buffer, position );
01286 x = ParseDouble( buffer, position );
01287 SkipCommaSpaces( buffer, position );
01288 y = ParseDouble( buffer, position );
01289 SkipCommaSpaces( buffer, position );
01290
01291 if (command == _T('c') || command == _T('s'))
01292 {
01293 x1 += lastx;
01294 y1 += lasty;
01295 x2 += lastx;
01296 y2 += lasty;
01297 x += lastx;
01298 y += lasty;
01299 }
01300
01301 prev = seg;
01302 if (command == _T('C') || command == _T('c'))
01303 seg = new a2dVpathCBCurveSegment( x, y, x1, y1 , x2, y2, a2dPATHSEG_CBCURVETO );
01304 else
01305 seg = new a2dVpathCBCurveSegment( *prev, x, y , x2, y2, a2dPATHSEG_CBCURVETO );
01306
01307 points->push_back( seg );
01308 lastx = x;
01309 lasty = y;
01310 }
01311 else
01312 break;
01313 SkipCommaSpaces( buffer, position );
01314 }
01315 break;
01316 }
01317 case _T('q'):
01318 case _T('Q'):
01319 case _T('t'):
01320 case _T('T'):
01321 {
01322 double x1=0.0,y1=0.0,x,y;
01323 for (;;)
01324 {
01325 current = buffer[ position ];
01326 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01327 {
01328
01329 if (command == _T('Q') || command == _T('q'))
01330 {
01331 x1 = ParseDouble( buffer, position );
01332 SkipCommaSpaces( buffer, position );
01333 y1 = ParseDouble( buffer, position );
01334 SkipCommaSpaces( buffer, position );
01335 }
01336 x = ParseDouble( buffer, position );
01337 SkipCommaSpaces( buffer, position );
01338 y = ParseDouble( buffer, position );
01339 SkipCommaSpaces( buffer, position );
01340
01341 if (command == _T('q') || command == _T('t'))
01342 {
01343 x1 += lastx;
01344 y1 += lasty;
01345 x += lastx;
01346 y += lasty;
01347 }
01348
01349 prev = seg;
01350 if (command == _T('Q') || command == _T('q'))
01351 seg = new a2dVpathQBCurveSegment( x, y, x1, y1, a2dPATHSEG_QBCURVETO );
01352 else
01353 seg = new a2dVpathQBCurveSegment( *prev, x, y, a2dPATHSEG_QBCURVETO );
01354 points->push_back( seg );
01355 lastx = x;
01356 lasty = y;
01357 }
01358 else
01359 break;
01360 SkipCommaSpaces( buffer, position );
01361 }
01362 break;
01363 }
01364 case _T('a'):
01365 case _T('A'):
01366 {
01367 double rx,ry,ax,x,y;
01368 for (;;)
01369 {
01370 current = buffer[ position ];
01371 if (current == wxT('+') || current == wxT('-') || wxIsdigit(current) )
01372 {
01373 rx = ParseDouble( buffer, position );
01374 SkipCommaSpaces( buffer, position );
01375 ry = ParseDouble( buffer, position );
01376 SkipCommaSpaces( buffer, position );
01377 ax = ParseDouble( buffer, position );
01378 SkipCommaSpaces( buffer, position );
01379
01380 current = buffer[ position ];
01381
01382 bool laf = false;
01383 switch (current)
01384 {
01385 case _T('0'):
01386 laf = false;
01387 break;
01388 case _T('1'):
01389 laf = true;
01390 break;
01391 }
01392 position++;
01393 SkipCommaSpaces( buffer, position );
01394 current = buffer[ position ];
01395
01396 bool sf = false;
01397 switch (current)
01398 {
01399 case _T('0'):
01400 sf = false;
01401 break;
01402 case _T('1'):
01403 sf = true;
01404 break;
01405 }
01406 position++;
01407
01408 SkipCommaSpaces( buffer, position );
01409 x = ParseDouble( buffer, position );
01410 SkipCommaSpaces( buffer, position );
01411 y = ParseDouble( buffer, position );
01412 SkipCommaSpaces( buffer, position );
01413
01414 if (command == _T('a'))
01415 {
01416 x += lastx;
01417 y += lasty;
01418 }
01419
01420 prev = seg;
01421 double xc,yc;
01422 double angle;
01423
01424 rsvg_path_arc( lastx, lasty, rx, ry, ax, laf, sf, x, y, &xc, &yc, &angle );
01425
01426 seg = new a2dVpathArcSegment( *prev, xc, yc, angle*180/M_PI );
01427
01428 points->push_back( seg );
01429 lastx = x;
01430 lasty = y;
01431 }
01432 else
01433 break;
01434 SkipCommaSpaces( buffer, position );
01435 }
01436 break;
01437 }
01438 default:
01439 {
01440 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("expected path command: '%s' at line %d"), buffer.c_str(), GetCurrentLineNumber());
01441 }
01442 }
01443 }
01444 catch (const a2dIOHandlerXMLException& e)
01445 {
01446 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("%s at line %d column %d"), e.getMessage().c_str(), e.getLineNumber(), e.getColumnNumber());
01447 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("expected path command: '%s' at line %d"), buffer.c_str(), GetCurrentLineNumber());
01448 }
01449 }
01450
01451 return true;
01452 }
01453
01454 bool a2dIOHandlerSVGIn::LoadSvgPath( a2dCanvasObject* parent )
01455 {
01456 if ( GetTagName() != _T("path") )
01457 return false;
01458
01459 a2dVpath* points = new a2dVpath();
01460
01461 if (!ParsePathPoints( points ))
01462 {
01463 delete points;
01464 wxString parseerror = _T("points missing in polygon");
01465 a2dDocviewGlobals->ReportErrorF( a2dError_XMLparse, _("SVG parsing error: '%s' at line %d"),
01466 parseerror.c_str(),
01467 GetCurrentLineNumber());
01468 return true;
01469 }
01470
01471 a2dVectorPath* path = new a2dVectorPath( points );
01472 m_currentobject = path;
01473 parent->Append( m_currentobject );
01474
01475 ParseSvgTransForm( m_currentobject );
01476 ParseSvgStyle( m_currentobject );
01477
01478 Next();
01479 Require( END_TAG, _T("path") );
01480 Next();
01481
01482 return true;
01483 }
01484
01485 bool a2dIOHandlerSVGIn::LoadSvgImage( a2dCanvasObject* parent )
01486 {
01487 if ( GetTagName() != _T("image") )
01488 return false;
01489
01490 a2dImage* Image = new a2dImage();
01491 m_currentobject = Image;
01492 parent->Append( m_currentobject );
01493
01494 ParseSvgTransForm( m_currentobject );
01495 ParseSvgStyle( m_currentobject );
01496
01497 Image->Translate( GetAttributeValueDouble( _T("x") ) , GetAttributeValueDouble( _T("y") ) );
01498
01499 Image->SetWidth( GetAttributeValueDouble( _T("width") ) );
01500 Image->SetHeight( GetAttributeValueDouble( _T("height") ) );
01501 Image->SetFilename( GetAttributeValue( _T("xlink:href")), wxBITMAP_TYPE_PNG );
01502
01503
01504 Next();
01505 Require( END_TAG, _T("image") );
01506 Next();
01507
01508 return true;
01509 }
01510
01511
01512
01513
01514
01515 a2dIOHandlerSVGOut::a2dIOHandlerSVGOut()
01516 {
01517 m_fill = a2dFill();
01518 m_stroke = *a2dNullSTROKE;
01519 m_showObject = NULL;
01520 m_ic = NULL;
01521 }
01522
01523 a2dIOHandlerSVGOut::~a2dIOHandlerSVGOut()
01524 {
01525 }
01526
01527 bool a2dIOHandlerSVGOut::CanSave( const wxObject* obj )
01528 {
01529 if ( !wxDynamicCast( obj, a2dCanvasDocument) )
01530 return false;
01531 return true;
01532 }
01533
01534 bool a2dIOHandlerSVGOut::Save( a2dDocumentOutputStream& stream, const wxObject* doc )
01535 {
01536 a2dIterC ic;
01537 m_doc = wxStaticCast( doc, a2dCanvasDocument);
01538
01539 if ( !m_showObject )
01540 m_showObject = m_doc->GetRootObject();
01541
01542 if ( !m_ic )
01543 {
01544 a2dCanvasView* drawer = wxDynamicCast( a2dDocviewGlobals->GetDocviewCommandProcessor()->GetCurrentView(),a2dCanvasView );
01545 if ( drawer )
01546 {
01547 ic = a2dIterC( drawer );
01548 m_ic = ⁣
01549 }
01550 }
01551
01552 wxASSERT_MSG( m_ic, wxT("No iteration context set while writing SVG output") );
01553 wxASSERT_MSG( m_ic->GetDrawer2D(), wxT("a2dIOHandlerSVGOut no a2dDrawer2D while writing SVG output") );
01554
01555 InitializeSave();
01556
01557 double Width = 1000;
01558 double Height = 1000;
01559 wxString unit = _T("um");
01560
01561 bool yaxis = m_ic->GetDrawer2D()->GetYaxis();
01562
01563
01564 a2dCanvasObject* root = m_ic->GetCanvasView()->GetShowObject();
01565
01566 a2dWalker_SetBoolProperty setp( PROPID_Check, false );
01567 setp.Start( root );
01568
01569 m_streamo = &stream;
01570
01571 WriteStartDocument( _T("1.0"), _T("UTF-8") , false );
01572 EndlWriteString ( _T("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ") );
01573
01574 EndlWriteString ( _T("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> ") );
01575
01576 WriteStartElementAttributes( _T("svg") );
01577
01578 WriteAttribute( _T("xmlns"),_T("http://www.w3.org/2000/svg") );
01579 WriteAttribute( _T("xmlns:xlink"),_T("http://www.w3.org/1999/xlink") );
01580
01581 wxString s;
01582 s.Printf ( _T(" width=\"%.2f%s\" height=\"%.2f%s\" viewBox=\"%f %f %f %f \" "),
01583 Width,unit.c_str(),Height,unit.c_str(),
01584 m_ic->GetDrawer2D()->GetVisibleMinX(),
01585 m_ic->GetDrawer2D()->GetVisibleMinY(),
01586 m_ic->GetDrawer2D()->GetVisibleWidth(),
01587 m_ic->GetDrawer2D()->GetVisibleHeight());
01588
01589
01590
01591 WriteString(s);
01592 WriteEndAttributes();
01593
01594 WriteElement( _T("title"), m_doc->GetPrintableName() );
01595 WriteElement( _T("desc"), m_doc->GetDescription() );
01596
01597 WriteStartElementAttributes( _T("g") );
01598 WriteAttribute( _T("style"),_T("fill:black; stroke:black; stroke-width:1") );
01599 WriteEndAttributes();
01600
01601 if ( yaxis )
01602 {
01603 WriteStartElementAttributes( _T("g") );
01604 WriteAttribute( _T("transform"),_T("scale( 1,-1)") );
01605 WriteEndAttributes();
01606 }
01607
01608 m_nameMap.clear();
01609
01610 Save( root, wxLAYER_ALL );
01611
01612 if ( yaxis )
01613 {
01614 WriteEndElement();
01615 }
01616
01617 WriteEndElement();
01618 WriteEndElement();
01619 WriteEndDocument();
01620
01621 ResetSave();
01622
01623 return true;
01624 }
01625
01626 wxString a2dIOHandlerSVGOut::UniqueName (wxString baseName)
01627 {
01628 if (m_nameMap.find(baseName) == m_nameMap.end())
01629 {
01630 m_nameMap[baseName] = 0;
01631 } else {
01632 ++m_nameMap[baseName];
01633 }
01634 baseName.Printf(_T("obj_%s_%d"), baseName.c_str(), m_nameMap[baseName]);
01635 return baseName;
01636 }
01637
01638
01639 void a2dIOHandlerSVGOut::Save( const a2dCanvasObject* object, int layer )
01640 {
01641 int objectlayer = object->GetLayer();
01642 a2dAffineMatrix lworld = object->GetTransformMatrix();
01643 if ( layer != objectlayer && layer != wxLAYER_ALL )
01644 {
01645 return;
01646 }
01647
01648 if( object->IsTemporary_DontSave())
01649 return;
01650
01651 const a2dShadowStyleProperty* shadow = object->GetShadowStyle();
01652
01653 if ( object->GetFill().GetType() == a2dFILL_GRADIENT_FILL_LINEAR || object->GetFill().GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01654 {
01655 SaveGradient( object->GetFill(), object );
01656 }
01657
01658 if ( shadow &&
01659 ( shadow->GetFill().GetType() == a2dFILL_GRADIENT_FILL_LINEAR || shadow->GetFill().GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01660 )
01661 {
01662 SaveGradient( shadow->GetFill(), object );
01663 }
01664
01665 wxString s;
01666 wxString url = object->GetURL();
01667
01668 if ( !url.IsEmpty() )
01669 {
01670 WriteStartElementAttributes( _T("a") );
01671 WriteAttribute( _T("xlink:href"), url );
01672 WriteAttribute( _T("id"), UniqueName(object->GetName()) );
01673 }
01674 else
01675 {
01676 WriteStartElementAttributes( _T("g") );
01677 WriteAttribute( _T("id"), UniqueName(object->GetName()) );
01678 }
01679
01680 if (!lworld.IsIdentity())
01681 {
01682 WriteNewLine();
01683 s.Printf ( _T("matrix( %f %f %f %f %f %f )"),
01684 lworld.GetValue(0,0), lworld.GetValue(0,1),
01685 lworld.GetValue(1,0), lworld.GetValue(1,1),
01686 lworld.GetValue(2,0), lworld.GetValue(2,1)
01687 );
01688 WriteAttribute( _T("transform"), s );
01689 WriteNewLine();
01690 }
01691
01692 SetSVGStyle( object->GetFill(), object->GetStroke(), object, layer );
01693
01694 WriteEndAttributes();
01695
01696 if ( shadow )
01697 {
01698 double dx = cos( shadow->GetExtrudeAngle() ) * shadow->GetExtrudeDepth();
01699 double dy = sin( shadow->GetExtrudeAngle() ) * shadow->GetExtrudeDepth();
01700
01701 WriteStartElementAttributes( _T("g") );
01702 s.Printf ( _T(" %f %f "), dx, dy );
01703 WriteAttribute( _T("translate"), s );
01704
01705 SetSVGStyle( shadow->GetFill(), shadow->GetStroke(), object, layer );
01706
01707 WriteEndAttributes();
01708
01709 DoSave( object, layer );
01710
01711 WriteEndElement();
01712 }
01713
01714 DoSave( object, layer );
01715
01716 a2dNamedPropertyList::const_iterator iter;
01717 for( iter = object->GetPropertyList().begin(); iter != object->GetPropertyList().end(); ++iter )
01718 {
01719 const a2dNamedProperty *prop = *iter;
01720 DoSaveProperty( object, prop, wxLAYER_ALL );
01721 }
01722
01723 const a2dCanvasObjectList* childobjects = object->GetChildObjectList();
01724
01725 if ( childobjects != wxNullCanvasObjectList )
01726 {
01727 a2dCanvasObjectList::const_iterator iter = childobjects->begin();
01728
01729 if ( iter != childobjects->end() )
01730 {
01731
01732
01733
01734
01735
01736 if ( ( layer == wxLAYER_ALL || object == m_ic->GetCanvasView()->GetShowObject() )
01737 &&
01738 m_doc->GetLayerSetup()
01739 )
01740 {
01741 unsigned int j;
01742 for ( j=0; j < wxMAXLAYER; j++ )
01743 {
01744 a2dLayerInfo* objlayer;
01745 if ( m_ic->GetCanvasView()->GetReverseOrder() )
01746 objlayer = m_doc->GetLayerSetup()->GetReverseOrderIndex()[j];
01747 else
01748 objlayer = m_doc->GetLayerSetup()->GetOrderIndex()[j];
01749
01750
01751
01752 if ( objlayer == wxNullLayerInfo )
01753 break;
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763 if ( objlayer->GetVisible() )
01764 {
01765 for( a2dCanvasObjectList::const_iterator iter2 = childobjects->begin(); iter2 != childobjects->end(); ++iter2 )
01766 {
01767 a2dCanvasObject *obj = (*iter2);
01768
01769 int olayer=obj->GetLayer();
01770
01771 if ( olayer == objlayer->GetLayer() )
01772 {
01773 Save( obj, objlayer->GetLayer() );
01774 }
01775 }
01776 }
01777 }
01778 }
01779 else
01780 {
01781 for( a2dCanvasObjectList::const_iterator iter2 = childobjects->begin(); iter2 != childobjects->end(); ++iter2 )
01782 {
01783 a2dCanvasObject *obj = (*iter2);
01784 int olayer = obj->GetLayer();
01785
01786 if ( olayer==layer)
01787 {
01788 Save( obj, layer );
01789 WriteNewLine();
01790 }
01791 }
01792 }
01793 }
01794 }
01795
01796 WriteNewLine();
01797 WriteEndElement();
01798 }
01799
01800 void a2dIOHandlerSVGOut::SaveGradient( const a2dFill& fill, const a2dCanvasObject* object )
01801 {
01802 if ( fill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
01803 {
01804 double x1 = fill.GetStart().m_x;
01805 double y1 = fill.GetStart().m_y;
01806 double x2 = fill.GetStop().m_x;
01807 double y2 = fill.GetStop().m_y;
01808
01809 if ( x1 == x2 && y1 == y2 )
01810 {
01811 x1 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMinX();
01812 y1 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMinY();
01813 x2 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMaxX();
01814 y2 = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetMaxY();
01815 }
01816
01817 WriteStartElementAttributes( _T("linearGradient") );
01818 WriteAttribute( _T("id"), fill.GetStamp() );
01819 WriteAttribute( _T("gradientUnits"), _T("userSpaceOnUse" ));
01820 WriteAttribute( _T("x1"), x1 );
01821 WriteAttribute( _T("y1"), y1 );
01822 WriteAttribute( _T("x2"), x2 );
01823 WriteAttribute( _T("y2"), y2 );
01824 WriteEndAttributes();
01825
01826 wxString s;
01827
01828 WriteStartElementAttributes( _T("stop") );
01829 WriteAttribute( _T("offset"), 0 );
01830 s.Printf ( _T("stop-color:#%s"), ColourToHex( fill.GetColour() ).c_str() );
01831 WriteAttribute( _T("style"), s );
01832 WriteEndAttributes();
01833 WriteEndElement();
01834
01835 WriteStartElementAttributes( _T("stop") );
01836 WriteAttribute( _T("offset"), 1 );
01837 s.Printf ( _T("stop-color:#%s"), ColourToHex( fill.GetColour2() ).c_str());
01838 WriteAttribute( _T("style"), s );
01839 WriteEndAttributes();
01840 WriteEndElement();
01841
01842 WriteEndElement();
01843 }
01844 else if ( fill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
01845 {
01846 double radius = fill.GetRadius();
01847
01848 if ( fill.GetRadius() == 0 )
01849 {
01850 radius = object->GetUnTransformedBbox( a2dCanvasObject::a2dCANOBJ_BBOX_CHILDREN ).GetWidth()/2.0;
01851 }
01852
01853 WriteStartElementAttributes( _T("radialGradient") );
01854 WriteAttribute( _T("id"), fill.GetStamp() );
01855 WriteAttribute( _T("gradientUnits"), _T("userSpaceOnUse") );
01856
01857 WriteAttribute( _T("cx"), fill.GetCenter().m_x );
01858 WriteAttribute( _T("cy"), fill.GetCenter().m_y );
01859 WriteAttribute( _T("r"), radius );
01860 WriteAttribute( _T("xfc"), fill.GetFocal().m_x );
01861 WriteAttribute( _T("yfc"), fill.GetFocal().m_y );
01862 WriteEndAttributes();
01863
01864 wxString s;
01865
01866 WriteStartElementAttributes( _T("stop") );
01867 WriteAttribute( _T("offset"), 0 );
01868 s.Printf ( _T("stop-color:#%s"), ColourToHex( fill.GetColour() ).c_str() );
01869 WriteAttribute( _T("style"), s );
01870 WriteEndAttributes();
01871 WriteEndElement();
01872
01873 WriteStartElementAttributes( _T("stop") );
01874 WriteAttribute( _T("offset"), 1 );
01875 s.Printf ( _T("stop-color:#%s"), ColourToHex( fill.GetColour2() ).c_str() );
01876 WriteAttribute( _T("style"), s );
01877 WriteEndAttributes();
01878 WriteEndElement();
01879
01880 WriteEndElement();
01881 }
01882 }
01883
01884 void a2dIOHandlerSVGOut::SetSVGStyle( const a2dFill& fill, const a2dStroke& stroke, const a2dCanvasObject* object, int WXUNUSED(layer) )
01885 {
01886 int objectlayer = object->GetLayer();
01887
01888 a2dLayers* layers = m_doc->GetLayerSetup();
01889
01890 a2dFill fillw;
01891 fillw = fill;
01892 a2dStroke strokew;
01893 strokew = stroke;
01894 if ( object->GetFilled() )
01895 {
01896 if ( fill.IsNoFill() )
01897 fillw = layers->GetFill( objectlayer);
01898 }
01899 else
01900 {
01901 fillw = *a2dTRANSPARENT_FILL;
01902 }
01903
01904 if ( stroke.IsNoStroke() )
01905 strokew = layers->GetStroke( objectlayer);
01906
01907 wxString s;
01908
01909 if ( strokew != *a2dINHERIT_STROKE )
01910 {
01911 if ( strokew.GetType() == a2dSTROKE_ONE_COLOUR )
01912 {
01913 wxString s2, s3 ;
01914
01915 if ( *a2dTRANSPARENT_STROKE != strokew )
01916 {
01917 s2 = _T(" stroke:#") + ColourToHex( strokew.GetColour() ) + _T("; ") ;
01918
01919 if ( strokew.GetPixelStroke() )
01920 {
01921 double worldwidth = m_ic->GetDrawer2D()->DeviceToWorldXRel( stroke.GetWidth() );
01922 s3.Printf ( _T("stroke-width:%f; "), worldwidth );
01923 }
01924 else
01925 {
01926 s3.Printf ( _T("stroke-width:%f; "), strokew.GetWidth() );
01927 }
01928
01929 if ( strokew.GetAlpha() < 255 )
01930 {
01931 wxString strokeAlpha;
01932 strokeAlpha.Printf
01933 (
01934 _T("stroke-opacity:%f; "),
01935 (double)(strokew.GetAlpha() / 255.0)
01936 );
01937 s3 = s3 + strokeAlpha;
01938 }
01939 if (strokew.GetStyle() != a2dSTROKE_SOLID)
01940 {
01941 wxString strokeDash;
01942 switch (strokew.GetStyle())
01943 {
01944 case a2dSTROKE_DOT:
01945 strokeDash = _T("stroke-dasharray: 0.3 0.3;");
01946 break;
01947 case a2dSTROKE_LONG_DASH:
01948 strokeDash = _T("stroke-dasharray: 1.5 0.5;");
01949 break;
01950 case a2dSTROKE_SHORT_DASH:
01951 strokeDash = _T("stroke-dasharray: 1 0.5;");
01952 break;
01953 case a2dSTROKE_DOT_DASH:
01954 strokeDash = _T("stroke-dasharray: 0.5 1 1.5 1;");
01955 break;
01956 case a2dSTROKE_USER_DASH:
01957 case a2dSTROKE_TRANSPARENT:
01958 case a2dSTROKE_BDIAGONAL_HATCH:
01959 case a2dSTROKE_CROSSDIAG_HATCH:
01960 case a2dSTROKE_FDIAGONAL_HATCH:
01961 case a2dSTROKE_CROSS_HATCH:
01962 case a2dSTROKE_HORIZONTAL_HATCH:
01963 case a2dSTROKE_VERTICAL_HATCH:
01964 case a2dSTROKE_STIPPLE:
01965 case a2dSTROKE_STIPPLE_MASK_OPAQUE:
01966 case a2dSTROKE_STIPPLE_MASK_OPAQUE_TRANSPARENT:
01967 case a2dSTROKE_OBJECTS:
01968 case a2dSTROKE_INHERIT:
01969 case a2dSTROKE_LAYER:
01970 case a2dSTROKE_NULLSTROKE:
01971 default:
01972
01973 break;
01974 };
01975 if (strokeDash.Length() > 0)
01976 {
01977 s3 = s3 + strokeDash;
01978 }
01979 }
01980 }
01981 else
01982 {
01983 s2 = _T(" stroke:none; ") ;
01984 }
01985 s = s2 + s3;
01986
01987 }
01988
01989
01990
01991
01992
01993
01994
01995 }
01996
01997 if ( fillw != *a2dINHERIT_FILL )
01998 {
01999 wxString s1(_T(""));
02000 if ( fillw.GetType() == a2dFILL_ONE_COLOUR )
02001 {
02002 if ( fillw.GetStyle() != a2dFILL_TRANSPARENT )
02003 {
02004 s1 = _T(" fill:#") + ColourToHex( fillw.GetColour()) + _T("; ") ;
02005 }
02006 else
02007 {
02008 s1 = _T(" fill:none; ") ;
02009 }
02010 }
02011 else if ( fillw.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
02012 {
02013 wxString gradientstamp;
02014 gradientstamp.Printf( _T("%d"), fillw.GetStamp() );
02015
02016 if ( fillw != *a2dTRANSPARENT_FILL )
02017 {
02018 s1 = _T(" fill-rule:nonzero; fill:url(#") + gradientstamp + _T("); ");
02019 }
02020 else
02021 {
02022 s1 = _T(" fill:none; ") ;
02023 }
02024
02025 }
02026 else if ( fillw.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
02027 {
02028 wxString gradientstamp;
02029 gradientstamp.Printf( _T("%d"), fillw.GetStamp() );
02030
02031 if ( fillw != *a2dTRANSPARENT_FILL )
02032 {
02033 s1 = _T(" fill-rule:nonzero; fill:url(#") + gradientstamp + _T("); ");
02034 }
02035 }
02036 else
02037 {
02038 s1 = _T(" fill:none; ") ;
02039 }
02040
02041 if (fillw.GetAlpha() < 255)
02042 {
02043 wxString fillAlpha;
02044 fillAlpha.Printf
02045 (
02046 _T("fill-opacity:%f; "),
02047 (double)(fillw.GetAlpha() / 255.0)
02048 );
02049 s1 = s1 + fillAlpha;
02050 }
02051
02052
02053 s = s + s1;
02054 }
02055
02056 a2dNamedPropertyList::const_iterator iter;
02057 for( iter = object->GetPropertyList().begin(); iter != object->GetPropertyList().end(); ++iter )
02058 {
02059 const a2dNamedProperty *prop = *iter;
02060 if ( wxDynamicCast( prop, a2dClipPathProperty) )
02061 {
02062 wxString s1;
02063 s1.Printf ( _T("clip-path:url(#%d)"), prop->GetRefObject()->GetUniqueSerializationId() );
02064 s = s + s1;
02065 }
02066 }
02067
02068 if ( !s.IsEmpty() )
02069 {
02070 *this << _T(" style = \" ") << s << _T(" \" ");
02071 }
02072 }
02073
02074 void a2dIOHandlerSVGOut::CreateSVGSpline
02075 (
02076 const a2dVertexList* vertexList,
02077 bool asPolygon,
02078 const wxString & style
02079 )
02080 {
02081
02082
02083
02084
02085 wxString s;
02086 WriteStartElementAttributes( _T("path") );
02087
02088 if (asPolygon)
02089 {
02090 if (style.Length() > 0)
02091 {
02092 WriteAttribute( _T("style"), style );
02093 } else {
02094 WriteAttribute( _T("style"), _T("fill-rule:nonzero; ") );
02095 }
02096 } else {
02097 WriteAttribute( _T("style"), _T("fill:none;") );
02098 }
02099 EndlWriteString(_T("d=\""));
02100
02101
02102 a2dVertexList::const_iterator iter = vertexList->begin();
02103
02104
02105 a2dLineSegment* point = *iter;
02106
02107 double x = point->m_x;
02108 double y = point->m_y;
02109 ++iter;
02110
02111 double xOld = x;
02112 double yOld = y;
02113
02114
02115 point = *iter;
02116 x = point->m_x;
02117 y = point->m_y;
02118 double xFirstMidpoint = xOld + 0.5*(x - xOld);
02119 double yFirstMidpoint = yOld + 0.5*(y - yOld);
02120
02121 if (asPolygon)
02122 {
02123
02124 s.Printf( _T("M %f,%f"), xFirstMidpoint, yFirstMidpoint );
02125 EndlWriteString(s);
02126 } else {
02127
02128
02129
02130
02131 s.Printf( _T("M %f,%f"), xOld, yOld );
02132 EndlWriteString(s);
02133
02134 s.Printf( _T("L %f,%f"), xFirstMidpoint, yFirstMidpoint);
02135 EndlWriteString(s);
02136 }
02137
02138
02139
02140
02141
02142
02143
02144
02145 for
02146 (
02147 ++iter;
02148 iter != vertexList->end();
02149 ++iter
02150 )
02151 {
02152 xOld = x;
02153 yOld = y;
02154 point = *iter;
02155 x = point->m_x;
02156 y = point->m_y;
02157
02158
02159
02160 s.Printf
02161 (
02162 _T("Q %f,%f,%f,%f"),
02163 xOld,
02164 yOld,
02165 xOld + 0.5*(x - xOld),
02166 yOld + 0.5*(y - yOld)
02167 );
02168 EndlWriteString (s);
02169 }
02170
02171 if (asPolygon)
02172 {
02173
02174 xOld = x;
02175 yOld = y;
02176 point = vertexList->front();
02177 x = point->m_x;
02178 y = point->m_y;
02179 s.Printf
02180 (
02181 _T("Q %f,%f,%f,%f"),
02182 xOld,
02183 yOld,
02184 xOld + 0.5*(x - xOld),
02185 yOld + 0.5*(y - yOld)
02186 );
02187 EndlWriteString(s);
02188
02189 s.Printf
02190 (
02191 _T("Q %f,%f,%f,%f"),
02192 x,
02193 y,
02194 xFirstMidpoint,
02195 yFirstMidpoint
02196 );
02197 EndlWriteString(s);
02198
02199 } else {
02200
02201 s.Printf (_T("L %f,%f"), x, y);
02202 EndlWriteString(s);
02203 }
02204
02205 EndlWriteString(_T("\"")) ;
02206 WriteEndAttributes();
02207 WriteEndElement();
02208 }
02209 void a2dIOHandlerSVGOut::CreateSVGSpline
02210 (
02211 const a2dVertexArray* vertexArray,
02212 bool asPolygon,
02213 const wxString & style
02214 )
02215 {
02216 a2dVertexList h;
02217 unsigned int i;
02218 for ( i = 0; i < vertexArray->size(); i++ )
02219 {
02220 h.push_back( vertexArray->Item( i )->Clone() );
02221 }
02222
02223 CreateSVGSpline(&h, asPolygon, style);
02224 }
02225
02226 void a2dIOHandlerSVGOut::DoSave( const a2dCanvasObject* object, int layer )
02227 {
02228 wxString s;
02229
02230
02231 if (0 != wxDynamicCast( object, a2dCanvasObjectArrayReference ))
02232 {
02233 a2dCanvasObjectArrayReference* obj = wxDynamicCast( object, a2dCanvasObjectArrayReference );
02234
02235 a2dAffineMatrix currentWorld = a2dIDENTITY_MATRIX;
02236
02237 a2dAffineMatrix offsetXY;
02238
02239 a2dAffineMatrix originalRef = obj->GetCanvasObject()->GetTransformMatrix();
02240
02241 int i,j;
02242 for ( i = 0 ; i < obj->GetRows(); i++)
02243 {
02244 for ( j = 0 ; j < obj->GetColumns(); j++)
02245 {
02246 a2dAffineMatrix tworld = currentWorld;
02247 tworld *= originalRef;
02248 obj->GetCanvasObject()->SetTransformMatrix( tworld );
02249 Save( obj->GetCanvasObject(), layer );
02250 obj->GetCanvasObject()->SetTransformMatrix( originalRef );
02251
02252 offsetXY.Translate( obj->GetHorzSpace(), 0 );
02253
02254 currentWorld = a2dIDENTITY_MATRIX;
02255 currentWorld *= offsetXY;
02256 }
02257
02258 offsetXY.Translate( -obj->GetHorzSpace()*obj->GetColumns(), obj->GetVertSpace() );
02259 currentWorld = a2dIDENTITY_MATRIX;
02260 currentWorld *= offsetXY;
02261 }
02262 }
02263
02264 else if (0 != wxDynamicCast( object, a2dCanvasObjectReference ))
02265 {
02266 a2dCanvasObjectReference* obj = wxDynamicCast( object, a2dCanvasObjectReference );
02267 Save( obj->GetCanvasObject(), layer );
02268 }
02269
02270 else if ( 0 != wxDynamicCast( object, a2dOrigin ))
02271 {
02272 a2dOrigin* obj = wxDynamicCast( object, a2dOrigin );
02273
02274 double w = (int) m_ic->GetDrawer2D()->DeviceToWorldXRel( obj->GetWidth() );
02275 double h = (int) m_ic->GetDrawer2D()->DeviceToWorldYRel( obj->GetHeight() );
02276
02277 s.Printf ( _T("M%f %f L %f %f"), -w, 0.0, w, 0.0 );
02278 WriteStartElementAttributes( _T("path") );
02279 WriteAttribute( _T("d"), s );
02280 WriteEndAttributes();
02281 WriteEndElement();
02282 s.Printf ( _T("M %f %f L %f %f"), 0.0, -h, 0.0, h );
02283 WriteStartElementAttributes( _T("path") );
02284 WriteAttribute( _T("d"), s );
02285 WriteEndAttributes();
02286 WriteEndElement();
02287 }
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335 else if (0 != wxDynamicCast( object, a2dArrow ))
02336 {
02337 a2dArrow* obj = wxDynamicCast( object, a2dArrow );
02338
02339 a2dPoint2D *cpoints = new a2dPoint2D[5];
02340 cpoints[0].m_x = 0 ; cpoints[0].m_y = 0;
02341 cpoints[1].m_x = obj->GetL1(); cpoints[1].m_y = obj->GetBase()/2;
02342 cpoints[2].m_x = obj->GetL2(); cpoints[2].m_y = 0;
02343 cpoints[3].m_x = obj->GetL1(); cpoints[3].m_y = -obj->GetBase()/2;
02344
02345 WriteStartElementAttributes( _T("polygon") );
02346
02347 wxPolygonFillMode fillStyle=wxWINDING_RULE;
02348 if ( fillStyle == wxODDEVEN_RULE )
02349 s = _T("fill-rule:evenodd; ");
02350 else
02351 s = _T("fill-rule:nonzero; ");
02352
02353 WriteAttribute( _T("style"), s );
02354 EndlWriteString(_T(" points=\""));
02355
02356 for (int i = 0; i < 5; i++)
02357 {
02358 s.Printf ( _T("%f,%f "), cpoints [i].m_x, cpoints[i].m_y);
02359 *this << s;
02360 }
02361
02362 EndlWriteString(_T("\"")) ;
02363 WriteEndAttributes(true);
02364
02365 delete [] cpoints;
02366 }
02367
02368 else if (0 != wxDynamicCast( object, a2dRectC ))
02369 {
02370 a2dRectC* obj = wxDynamicCast( object, a2dRectC );
02371
02372
02373 double x = - obj->GetWidth()/2;
02374 double y = - obj->GetHeight()/2;
02375
02376 WriteStartElementAttributes( _T("rect") );
02377 WriteAttribute( _T("x"), x );
02378 WriteAttribute( _T("y"), y );
02379 WriteAttribute( _T("width"), obj->GetWidth() );
02380 WriteAttribute( _T("height"), obj->GetHeight() );
02381
02382 if ( obj->GetRadius() != 0 )
02383 WriteAttribute( _T("rx"), obj->GetRadius() );
02384
02385 WriteEndAttributes(true);
02386 }
02387
02388 else if (0 != wxDynamicCast( object, a2dRect ))
02389 {
02390 a2dRect* obj = wxDynamicCast( object, a2dRect );
02391
02392
02393 double x = 0;
02394 double y = 0;
02395
02396 WriteStartElementAttributes( _T("rect") );
02397 WriteAttribute( _T("x"), x );
02398 if ( obj->GetHeight() < 0 )
02399 {
02400 WriteAttribute( _T("y"), obj->GetHeight() );
02401 WriteAttribute( _T("width"), obj->GetWidth() );
02402 WriteAttribute( _T("height"), -obj->GetHeight() );
02403 }
02404 else
02405 {
02406 WriteAttribute( _T("y"), y );
02407 WriteAttribute( _T("width"), obj->GetWidth() );
02408 WriteAttribute( _T("height"), obj->GetHeight() );
02409 }
02410
02411 if ( obj->GetRadius() != 0 )
02412 WriteAttribute( _T("rx"), obj->GetRadius() );
02413
02414 WriteEndAttributes(true);
02415 }
02416
02417 else if (0 != wxDynamicCast( object, a2dCircle ))
02418 {
02419 a2dCircle* obj = wxDynamicCast( object, a2dCircle );
02420
02421 WriteStartElementAttributes( _T("circle") );
02422 WriteAttribute( _T("cx"), 0 );
02423 WriteAttribute( _T("cy"), 0 );
02424 WriteAttribute( _T("r"), obj->GetRadius() );
02425
02426 WriteEndAttributes(true);
02427 }
02428
02429 else if (0 != wxDynamicCast( object, a2dEllipse ))
02430 {
02431 a2dEllipse* obj = wxDynamicCast( object, a2dEllipse );
02432
02433 double rh = obj->GetHeight()/2 ;
02434 double rw = obj->GetWidth()/2 ;
02435
02436
02437 WriteStartElementAttributes( _T("ellipse") );
02438 WriteAttribute( _T("cx"), 0 );
02439 WriteAttribute( _T("cy"), 0 );
02440 WriteAttribute( _T("rx"), rw );
02441 WriteAttribute( _T("ry"), rh );
02442
02443 WriteEndAttributes(true);
02444 }
02445
02446 else if (0 != wxDynamicCast( object, a2dEllipticArc ))
02447 {
02448 a2dEllipticArc* obj = wxDynamicCast( object, a2dEllipticArc );
02449
02450
02451
02452
02453 a2dStroke pen = object->GetStroke();
02454
02455
02456
02457
02458
02459
02460
02461 wxString s, s1, s2, s3 ;
02462
02463 a2dFill fill = object->GetFill();
02464
02465 double xc = 0;
02466 double yc = 0;
02467
02468 double rx = obj->GetHeight()/2 ;
02469 double ry = obj->GetWidth()/2 ;
02470
02471 double xs, ys, xe, ye ;
02472 xs = xc + rx * cos (wxDegToRad(obj->GetStart() )) ;
02473 xe = xc + rx * cos (wxDegToRad(obj->GetEnd())) ;
02474 ys = yc - ry * sin (wxDegToRad(obj->GetStart())) ;
02475 ye = yc - ry * sin (wxDegToRad(obj->GetEnd())) ;
02476
02477
02478
02479 double theta1 = atan2(yc-ys,xs-xc);
02480 if ( theta1 < 0 ) theta1 = theta1 + wxPI * 2;
02481 double theta2 = atan2(yc-ye, xe-xc);
02482 if ( theta2 < 0 ) theta2 = theta2 + wxPI * 2;
02483 if ( theta2 < theta1 ) theta2 = theta2 + wxPI *2 ;
02484
02485 bool fArc;
02486 if ( fabs( (theta2 - theta1) ) > wxPI ) fArc = true; else fArc = false;
02487
02488 bool fSweep = false;
02489
02490 if ( fill != *a2dTRANSPARENT_FILL )
02491 {
02492 WriteStartElementAttributes( _T("path") );
02493
02494
02495 s.Printf ( _T("M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z"),
02496 xs, ys, rx, ry, fArc? _T("1"): _T("0") , fSweep? _T("1"): _T("0"),xe, ye, xc, yc );
02497 WriteAttribute( _T("d"), s );
02498 WriteAttribute( _T("style"), _T("stroke:none; ") );
02499 WriteEndAttributes();
02500 WriteEndElement();
02501 }
02502
02503 if (pen != *a2dTRANSPARENT_STROKE)
02504 {
02505
02506 WriteStartElementAttributes( _T("path") );
02507
02508
02509 s.Printf ( _T("M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z"),
02510 xs, ys, rx, ry, fArc? _T("1"): _T("0") , fSweep? _T("1"): _T("0"),xe, ye, xc, yc );
02511
02512
02513
02514
02515 WriteAttribute( _T("d"), s );
02516 WriteAttribute( _T("style"), _T("fill:none; ") );
02517 WriteEndAttributes();
02518 WriteEndElement();
02519
02520
02521 }
02522 }
02523
02524 else if (0 != wxDynamicCast( object, a2dArc ))
02525 {
02526 a2dArc* obj = wxDynamicCast( object, a2dArc );
02527
02528
02529
02530
02531 a2dStroke pen = object->GetStroke();
02532
02533 wxString s, s1, s2, s3 ;
02534
02535 a2dFill fill = object->GetFill();
02536
02537 double xc = 0;
02538 double yc = 0;
02539
02540 double dx = obj->GetX1();
02541 double dy = obj->GetY1();
02542 double radius = sqrt(dx*dx+dy*dy);
02543
02544 double start = wxRadToDeg(atan2(dy, dx));
02545
02546 dx = obj->GetX2();
02547 dy = obj->GetY2();
02548 double end = wxRadToDeg(atan2(dy, dx));
02549
02550 double rx = radius;
02551 double ry = radius;
02552
02553 double xs, ys, xe, ye ;
02554 if ( m_ic->GetDrawer2D()->GetYaxis())
02555 {
02556 xs = xc + rx * cos (wxDegToRad(start)) ;
02557 xe = xc + rx * cos (wxDegToRad(end)) ;
02558 ys = yc + ry * sin (wxDegToRad(start)) ;
02559 ye = yc + ry * sin (wxDegToRad(end)) ;
02560 }
02561 else
02562 {
02563 xe = xc + rx * cos (wxDegToRad(start)) ;
02564 xs = xc + rx * cos (wxDegToRad(end)) ;
02565 ye = yc + ry * sin (wxDegToRad(start)) ;
02566 ys = yc + ry * sin (wxDegToRad(end)) ;
02567 }
02568
02569
02570
02571 double theta1 = atan2(yc-ys,xs-xc);
02572 if ( theta1 < 0 ) theta1 = theta1 + wxPI * 2;
02573 double theta2 = atan2(yc-ye, xe-xc);
02574 if ( theta2 < 0 ) theta2 = theta2 + wxPI * 2;
02575 if ( theta2 < theta1 ) theta2 = theta2 + wxPI *2 ;
02576
02577 bool fArc;
02578 if ( fabs( (theta2 - theta1) ) > wxPI ) fArc = true; else fArc = false;
02579
02580 bool fSweep = false;
02581
02582 if ( fill != *a2dTRANSPARENT_FILL )
02583 {
02584 WriteStartElementAttributes( _T("path") );
02585
02586
02587 s.Printf ( _T("M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z"),
02588 xs, ys, rx, ry, fArc? _T("1"): _T("0") , fSweep? _T("1"): _T("0"),xe, ye, xc, yc );
02589 WriteAttribute( _T("d"), s );
02590 WriteAttribute( _T("style"), _T("stroke:none; ") );
02591 WriteEndAttributes();
02592 WriteEndElement();
02593 }
02594
02595 if (pen != *a2dTRANSPARENT_STROKE)
02596 {
02597
02598 WriteStartElementAttributes( _T("path") );
02599
02600
02601 s.Printf ( _T("M%f %f A%f %f 0.0 %s %s %f %f L%f %f Z"),
02602 xs, ys, rx, ry, fArc? _T("1"): _T("0") , fSweep? _T("1"): _T("0"),xe, ye, xc, yc );
02603
02604
02605
02606
02607 WriteAttribute( _T("d"), s );
02608 WriteAttribute( _T("style"), _T("fill:none; ") );
02609 WriteEndAttributes();
02610 WriteEndElement();
02611 }
02612 }
02613
02614 else if (0 != wxDynamicCast( object, a2dEndsLine ))
02615 {
02616 a2dEndsLine* obj = wxDynamicCast( object, a2dEndsLine );
02617
02618 double x1 = obj->GetPosX1(false);
02619 double y1 = obj->GetPosY1(false);
02620 double x2 = obj->GetPosX2(false);
02621 double y2 = obj->GetPosY2(false);
02622 double xscale = obj->GetEndScaleX();
02623 double yscale = obj->GetEndScaleY();
02624
02625 WriteStartElementAttributes( _T("path") );
02626 s.Printf ( _T("M%f %f L%f %f"), x1, y1, x2, y2 );
02627 WriteAttribute( _T("d"), s );
02628 WriteEndAttributes();
02629 WriteEndElement();
02630
02631 if ( obj->GetBegin())
02632 {
02633 double dx, dy;
02634 dx = x2-x1;
02635 dy = y2-y1;
02636 double ang1;
02637 if (!dx && !dy)
02638 ang1 = 0;
02639 else
02640 ang1 = wxRadToDeg(atan2(dy, dx));
02641
02642 a2dAffineMatrix lworld;
02643
02644 lworld.Scale( xscale, yscale, 0, 0);
02645 lworld.Rotate(-ang1);
02646 lworld.Translate(x1,y1);
02647
02648 WriteStartElementAttributes( _T("g") );
02649 s.Printf ( _T("matrix( %f %f %f %f %f %f )"),
02650 lworld.GetValue(0,0), lworld.GetValue(0,1),
02651 lworld.GetValue(1,0), lworld.GetValue(1,1),
02652 lworld.GetValue(2,0), lworld.GetValue(2,1)
02653 );
02654 WriteAttribute( _T("transform"), s );
02655 WriteEndAttributes();
02656
02657 Save( obj->GetBegin(), layer );
02658
02659 WriteEndElement();
02660 }
02661
02662 if ( obj->GetEnd())
02663 {
02664 double dx, dy;
02665 dx = x2-x1;
02666 dy = y2-y1;
02667 double ang2;
02668 if (!dx && !dy)
02669 ang2 = 0;
02670 else
02671 ang2 = wxRadToDeg(atan2(-dy, -dx));
02672
02673 a2dAffineMatrix lworld;
02674
02675 lworld.Scale(xscale,yscale,0,0);
02676 lworld.Rotate(-ang2);
02677 lworld.Translate(x2,y2);
02678
02679 WriteStartElementAttributes( _T("g") );
02680 s.Printf ( _T("matrix( %f %f %f %f %f %f )"),
02681 lworld.GetValue(0,0), lworld.GetValue(0,1),
02682 lworld.GetValue(1,0), lworld.GetValue(1,1),
02683 lworld.GetValue(2,0), lworld.GetValue(2,1)
02684 );
02685 WriteAttribute( _T("transform"), s );
02686 WriteEndAttributes();
02687
02688 Save( obj->GetEnd(), layer );
02689
02690 WriteEndElement();
02691 }
02692 }
02693
02694 else if (0 != wxDynamicCast( object, a2dSLine ))
02695 {
02696 a2dSLine* obj = wxDynamicCast( object, a2dSLine );
02697
02698 WriteStartElementAttributes( _T("path") );
02699 s.Printf ( _T("M%f %f L%f %f"), obj->GetPosX1(false), obj->GetPosY1(false), obj->GetPosX2(false), obj->GetPosY2(false) );
02700 WriteAttribute( _T("d"), s );
02701 WriteEndAttributes();
02702 WriteEndElement();
02703 }
02704
02705 else if (0 != wxDynamicCast( object, a2dImage ))
02706 {
02707 a2dImage* obj = wxDynamicCast( object, a2dImage );
02708
02709 double width = obj->GetWidth();
02710 double height = obj->GetHeight();
02711
02712
02713 double x = -width/2;
02714 double y = -height/2;
02715
02716 WriteStartElementAttributes( _T("image") );
02717 WriteAttribute( _T("x"), x );
02718 WriteAttribute( _T("y"), y );
02719 WriteAttribute( _T("width"), width );
02720 WriteAttribute( _T("height"), height );
02721 WriteAttribute( _T("xlink:href"), obj->GetFilename() );
02722 WriteEndAttributes();
02723 WriteEndElement();
02724 }
02725
02726 else if (0 != wxDynamicCast( object, a2dText ))
02727 {
02728 a2dText* obj = wxDynamicCast( object, a2dText );
02729
02730
02731
02732 const a2dFontInfo &font = obj->GetFont().GetFontInfo();
02733
02734 wxString fontFamily =
02735 (font.GetName().Length() > 0)
02736 ? font.GetName()
02737 : _T("Verdana, Arial, sans-serif");
02738
02739 wxString fontStyleBold =
02740 (font.GetStyle().Lower().Find(_T("bold")) != -1)
02741 ? _T("font-weight:bold; ")
02742 : (font.GetStyle().Lower().Find(_T("light")) != -1)
02743 ? _T("font-weight:lighter; ")
02744 : _T("");
02745
02746 wxString fontStyleItalic =
02747 (font.GetStyle().Lower().Find(_T("italic")) != -1)
02748 ? _T("font-style:italic; ")
02749 : (font.GetStyle().Lower().Find(_T("slant")) != -1)
02750 ? _T("font-style:oblique; ")
02751 : _T("");
02752
02753
02754 wxString alignmentH =
02755 (obj->GetAlignment() & (wxRIGHT | wxALIGN_RIGHT))
02756 ? _T("end")
02757 : (obj->GetAlignment() & (wxLEFT | wxALIGN_LEFT))
02758 ? _T("start")
02759 : _T("middle");
02760
02761 wxString alignmentV =
02762 (obj->GetAlignment() & (wxBOTTOM | wxALIGN_BOTTOM))
02763 ? _T("-100%")
02764 : (obj->GetAlignment() & (wxALIGN_CENTER_VERTICAL))
02765 ? _T("-50%")
02766 : _T("0%");
02767
02768 wxString color = ColourToHex( obj->GetStroke().GetColour());
02769
02770 s.Printf
02771 (
02772 _T("font-family:%s; ")
02773 _T("font-size:%fpt; ")
02774 _T("fill:#%s; ")
02775 _T("stroke:#%s; ")
02776 _T("text-anchor:%s; ")
02777 _T("baseline-shift:%s; ")
02778 _T("%s%s"),
02779 fontFamily.c_str(),
02780 obj->GetTextHeight(),
02781 #if wxCHECK_VERSION(2, 9, 0)
02782 color.GetData().AsChar(),
02783 color.GetData().AsChar(),
02784 alignmentH.GetData().AsChar(),
02785 alignmentV.GetData().AsChar(),
02786 fontStyleBold.GetData().AsChar(),
02787 fontStyleItalic.GetData().AsChar()
02788 #else
02789 color.c_str(),
02790 color.c_str(),
02791 alignmentH.c_str(),
02792 alignmentV.c_str(),
02793 fontStyleBold.c_str(),
02794 fontStyleItalic.c_str()
02795 #endif
02796 );
02797
02798 WriteStartElementAttributes( _T("text") );
02799 WriteAttribute( _T("x"), 0 );
02800 WriteAttribute( _T("y"), 0 );
02801 WriteAttribute( _T("style"), s );
02802 WriteEndAttributes();
02803
02804
02805
02806
02807 WriteContent( obj->GetText() );
02808 WriteEndElement();
02809 }
02810
02811 else if (0 != wxDynamicCast( object, a2dPolylineL ))
02812 {
02813 a2dPolylineL* obj = wxDynamicCast( object, a2dPolylineL );
02814
02815 a2dVertexList* points = obj->GetSegments();
02816
02817 if ( obj->GetSpline() && (points->size() > 2) )
02818 {
02819 CreateSVGSpline (points);
02820 } else {
02821
02822
02823 WriteStartElementAttributes( _T("polyline") );
02824
02825 WriteAttribute( _T("style"), _T("fill:none;") );
02826 EndlWriteString(_T(" points=\""));
02827
02828 unsigned int i=0;
02829 for
02830 (
02831 a2dVertexList::iterator iter = points->begin();
02832 iter != points->end();
02833 ++iter
02834 )
02835 {
02836 a2dLineSegment* point = *iter;
02837 s.Printf ( _T("%f,%f "), point->m_x, point->m_y );
02838 if (i%6==0)
02839 WriteNewLine();
02840 WriteString(s) ;
02841 i++;
02842 }
02843
02844 EndlWriteString(_T("\"")) ;
02845 WriteEndAttributes();
02846 WriteEndElement();
02847 }
02848
02849
02850
02851
02852 double xscale = obj->GetEndScaleX();
02853 double yscale = obj->GetEndScaleY();
02854
02855 if ( obj->GetBegin() )
02856 {
02857 a2dVertexList::iterator iter = points->begin();
02858 a2dLineSegment* point1 = *iter;
02859 iter++;
02860 a2dLineSegment* point2 = *iter;
02861
02862 double dx, dy;
02863 dx = point2->m_x - point1->m_x;
02864 dy = point2->m_y - point1->m_y;
02865
02866 double ang1;
02867 if (!dx && !dy)
02868 ang1=0;
02869 else
02870 ang1 = wxRadToDeg(atan2(dy,dx));
02871
02872 a2dAffineMatrix lworld;
02873
02874 lworld.Scale(xscale,yscale,0,0);
02875 lworld.Rotate(-ang1);
02876 lworld.Translate(point1->m_x,point1->m_y);
02877
02878 WriteStartElementAttributes( _T("g") );
02879 s.Printf ( _T("matrix( %f %f %f %f %f %f )"),
02880 lworld.GetValue(0,0), lworld.GetValue(0,1),
02881 lworld.GetValue(1,0), lworld.GetValue(1,1),
02882 lworld.GetValue(2,0), lworld.GetValue(2,1)
02883 );
02884 WriteAttribute( _T("transform"), s );
02885 WriteEndAttributes();
02886
02887 Save( obj->GetBegin(), layer );
02888
02889 WriteEndElement();
02890 }
02891
02892 if ( obj->GetEnd() )
02893 {
02894 a2dVertexList::reverse_iterator iter = points->rbegin();
02895 a2dLineSegment* point1 = *iter;
02896 iter++;
02897 a2dLineSegment* point2 = *iter;
02898
02899 double dx, dy;
02900 dx=point2->m_x-point1->m_x;
02901 dy=point2->m_y-point1->m_y;
02902 double ang2;
02903 if (!dx && !dy)
02904 ang2=0;
02905 else
02906 ang2 = wxRadToDeg(atan2(dy,dx));
02907
02908 a2dAffineMatrix lworld;
02909
02910 lworld.Scale(xscale,yscale,0,0);
02911 lworld.Rotate(-ang2);
02912 lworld.Translate(point1->m_x,point1->m_y);
02913
02914 WriteStartElementAttributes( _T("g") );
02915 s.Printf ( _T("matrix( %f %f %f %f %f %f )"),
02916 lworld.GetValue(0,0), lworld.GetValue(0,1),
02917 lworld.GetValue(1,0), lworld.GetValue(1,1),
02918 lworld.GetValue(2,0), lworld.GetValue(2,1)
02919 );
02920 WriteAttribute( _T("transform"), s );
02921 WriteEndAttributes();
02922
02923 Save( obj->GetEnd(), layer );
02924
02925 WriteEndElement();
02926 }
02927
02928 }
02929
02930 else if (0 != wxDynamicCast( object, a2dPolygonL ))
02931 {
02932 a2dPolygonL* obj = wxDynamicCast( object, a2dPolygonL );
02933
02934 a2dVertexList* points = obj->GetSegments();
02935 wxPolygonFillMode fillStyle=wxWINDING_RULE;
02936 if ( fillStyle == wxODDEVEN_RULE )
02937 s = _T("fill-rule:evenodd; ");
02938 else
02939 s = _T("fill-rule:nonzero; ");
02940
02941 if ( obj->GetSpline() && (points->size() > 2) )
02942 {
02943 CreateSVGSpline(points, true, s);
02944 } else {
02945 WriteStartElementAttributes( _T("polygon") );
02946
02947 WriteAttribute( _T("style"), s );
02948 WriteNewLine();
02949 EndlWriteString(_T(" points=\""));
02950
02951 unsigned int i=0;
02952 for
02953 (
02954 a2dVertexList::iterator iter = points->begin();
02955 iter != points->end();
02956 ++iter
02957 )
02958 {
02959 a2dLineSegment* seg = *iter;
02960 if (i%6==0)
02961 WriteNewLine();
02962 s.Printf ( _T("%f,%f "), seg->m_x, seg->m_y);
02963 WriteString( s );
02964 i++;
02965 }
02966 WriteString(_T("\"")) ;
02967 WriteNewLine();
02968 WriteEndAttributes();
02969 WriteEndElement();
02970 }
02971 }
02972
02973 else if (0 != wxDynamicCast( object, a2dVectorPath ))
02974 {
02975 a2dVectorPath* obj = wxDynamicCast( object, a2dVectorPath );
02976
02977 WriteStartElementAttributes( _T("path") );
02978 WriteString( _T(" d=\""));
02979
02980 unsigned int i;
02981 for (i=0; i < obj->GetCount();i++)
02982 {
02983 a2dVpathSegment& seg = obj->GetSegments()->Item(i);
02984
02985 switch ( seg.m_type )
02986 {
02987 case a2dPATHSEG_MOVETO:
02988 {
02989 s.Printf ( _T("M %f %f "), seg.m_x1, seg.m_y1 );
02990 break;
02991 }
02992 case a2dPATHSEG_LINETO:
02993 {
02994 s.Printf ( _T("L %f %f "), seg.m_x1, seg.m_y1 );
02995 break;
02996 }
02997 case a2dPATHSEG_LINETO_NOSTROKE:
02998 {
02999
03000 s.Printf ( _T("L %f %f "), seg.m_x1, seg.m_y1 );
03001 break;
03002 }
03003
03004 case a2dPATHSEG_CBCURVETO:
03005 {
03006 a2dVpathCBCurveSegment& cseg = (a2dVpathCBCurveSegment&) seg;
03007 s.Printf ( _T("C %f %f %f %f %f %f "), cseg.m_x2, cseg.m_y2, cseg.m_x3, cseg.m_y3, cseg.m_x1, cseg.m_y1 );
03008 break;
03009 }
03010 case a2dPATHSEG_CBCURVETO_NOSTROKE:
03011 {
03012 a2dVpathCBCurveSegment& cseg = (a2dVpathCBCurveSegment&) seg;
03013 s.Printf ( _T("C %f %f %f %f %f %f "), cseg.m_x2, cseg.m_y2, cseg.m_x3, cseg.m_y3, cseg.m_x1, cseg.m_y1 );
03014 break;
03015 }
03016
03017 case a2dPATHSEG_QBCURVETO:
03018 {
03019 a2dVpathQBCurveSegment& cseg = (a2dVpathQBCurveSegment&) seg;
03020 s.Printf ( _T("T %f %f %f %f "), cseg.m_x2, cseg.m_y2, cseg.m_x1, cseg.m_y1 );
03021 break;
03022 }
03023 case a2dPATHSEG_QBCURVETO_NOSTROKE:
03024 {
03025 a2dVpathQBCurveSegment& cseg = (a2dVpathQBCurveSegment&) seg;
03026 s.Printf ( _T("T %f %f %f %f "), cseg.m_x2, cseg.m_y2, cseg.m_x1, cseg.m_y1 );
03027 break;
03028 }
03029
03030 case a2dPATHSEG_ARCTO:
03031 {
03032
03033 a2dVpathArcSegment& cseg = (a2dVpathArcSegment&) seg;
03034 s.Printf ( _T("T %f %f %f %f "), cseg.m_x2, cseg.m_y2, cseg.m_x1, cseg.m_y1 );
03035 break;
03036 }
03037 case a2dPATHSEG_ARCTO_NOSTROKE:
03038 {
03039
03040 a2dVpathArcSegment& cseg = (a2dVpathArcSegment&) seg;
03041 s.Printf ( _T("T %f %f %f %f "), cseg.m_x2, cseg.m_y2, cseg.m_x1, cseg.m_y1 );
03042 break;
03043 }
03044 default:
03045 break;
03046 }
03047
03048 WriteString( s);
03049
03050 switch ( seg.GetClose() )
03051 {
03052 case a2dPATHSEG_END_CLOSED:
03053 {
03054 WriteString( _T(" Z"));
03055 break;
03056 }
03057 case a2dPATHSEG_END_CLOSED_NOSTROKE:
03058 {
03059 WriteString( _T(" Z"));
03060 break;
03061 }
03062 default:
03063 break;
03064 }
03065
03066 if (i%2==0)
03067 WriteNewLine();
03068 }
03069
03070 WriteString(_T("\"")) ;
03071 WriteEndAttributes();
03072 WriteEndElement();
03073 }
03074
03075 }
03076
03077 void a2dIOHandlerSVGOut::DoSaveProperty( const a2dCanvasObject* WXUNUSED(object), const a2dNamedProperty* property, int layer )
03078 {
03079 wxString s;
03080 if ( 0 != wxDynamicCast( property, a2dClipPathProperty ))
03081 {
03082 a2dClipPathProperty* prop = wxDynamicCast( property, a2dClipPathProperty );
03083
03084
03085 if ( prop->GetClipObject() )
03086 {
03087 WriteStartElement( _T("defs") );
03088 WriteStartElementAttributes( _T("clipPath") );
03089 WriteAttribute( _T("id"), prop->GetRefObject()->GetUniqueSerializationId() );
03090
03091
03092
03093
03094
03095 a2dAffineMatrix lworld = prop->GetClipObject()->GetTransformMatrix();
03096 if (!lworld.IsIdentity())
03097 {
03098 s.Printf ( _T("matrix( %f %f %f %f %f %f )"),
03099 lworld.GetValue(0,0), lworld.GetValue(0,1),
03100 lworld.GetValue(1,0), lworld.GetValue(1,1),
03101 lworld.GetValue(2,0), lworld.GetValue(2,1)
03102 );
03103 WriteAttribute( _T("transform"), s );
03104 }
03105
03106 SetSVGStyle( prop->GetClipObject()->GetFill(), prop->GetClipObject()->GetStroke(), prop->GetClipObject(), layer );
03107 WriteEndAttributes();
03108
03109 a2dCanvasObjectList* childobjects = prop->GetClipObject()->GetChildObjectList();
03110
03111
03112
03113
03114
03115
03116 if ( childobjects != wxNullCanvasObjectList )
03117 {
03118 forEachIn( a2dCanvasObjectList, childobjects )
03119 DoSave( (*iter), layer );
03120 }
03121
03122 WriteEndElement();
03123 WriteEndElement();
03124 }
03125
03126 if ( prop->GetVisible() )
03127 {
03128 SetSVGStyle( prop->GetClipObject()->GetFill(), prop->GetClipObject()->GetStroke(), prop->GetClipObject(), layer );
03129 Save( prop->GetClipObject(), layer );
03130 }
03131
03132 }
03133 else if ( 0 != wxDynamicCast( property, a2dProperty ) &&
03134 property->GetCanRender() && property->GetVisible() )
03135 {
03136 Save( (a2dCanvasObject*) property->GetRefObject(), layer );
03137 }
03138 }