karbon

vcomposite.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001, 2002, 2003 The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qdom.h>
00021 #include <qpainter.h>
00022 #include <qwmatrix.h>
00023 #include <qregexp.h>
00024 
00025 #include <KoPoint.h>
00026 #include <KoRect.h>
00027 #include <KoUnit.h>
00028 #include <KoStore.h>
00029 #include <KoXmlWriter.h>
00030 #include <KoXmlNS.h>
00031 #include <KoGenStyles.h>
00032 
00033 #include "vcomposite.h"
00034 #include "vcomposite_iface.h"
00035 #include "vfill.h"
00036 #include "vpainter.h"
00037 #include "vsegment.h"
00038 #include "vstroke.h"
00039 #include "vvisitor.h"
00040 #include "vpath.h"
00041 #include "commands/vtransformcmd.h"
00042 #include "vdocument.h"
00043 
00044 #include <kdebug.h>
00045 
00046 
00047 VPath::VPath( VObject* parent, VState state )
00048     : VObject( parent, state ), m_fillRule( winding )
00049 {
00050     m_paths.setAutoDelete( true );
00051 
00052     // add an initial path:
00053     m_paths.append( new VSubpath( this ) );
00054 
00055     // we need a stroke for boundingBox() at anytime:
00056     m_stroke = new VStroke( this );
00057     m_fill = new VFill();
00058 
00059     m_drawCenterNode = false;
00060 }
00061 
00062 VPath::VPath( const VPath& composite )
00063     : VObject( composite ), SVGPathParser()
00064 {
00065     m_paths.setAutoDelete( true );
00066 
00067     VSubpath* path;
00068 
00069     VSubpathListIterator itr( composite.m_paths );
00070     for( itr.toFirst(); itr.current(); ++itr )
00071     {
00072         path = itr.current()->clone();
00073         path->setParent( this );
00074         m_paths.append( path );
00075     }
00076 
00077     if ( composite.stroke() )
00078         setStroke( *composite.stroke() );
00079 
00080     if ( composite.fill() )
00081         setFill( *composite.fill() );
00082 
00083     m_drawCenterNode = false;
00084     m_fillRule = composite.m_fillRule;
00085     m_matrix = composite.m_matrix;
00086 }
00087 
00088 VPath::~VPath()
00089 {
00090 }
00091 
00092 DCOPObject* VPath::dcopObject()
00093 {
00094     if ( !m_dcop )
00095         m_dcop = new VPathIface( this );
00096 
00097     return m_dcop;
00098 }
00099 
00100 
00101 void
00102 VPath::draw( VPainter* painter, const KoRect *rect ) const
00103 {
00104     if(
00105         state() == deleted ||
00106         state() == hidden ||
00107         state() == hidden_locked )
00108     {
00109         return;
00110     }
00111 
00112     if( rect && !rect->intersects( boundingBox() ) )
00113         return;
00114 
00115     painter->save();
00116 
00117     VSubpathListIterator itr( m_paths );
00118 
00119     // draw simplistic contour:
00120     if( state() == edit )
00121     {
00122         for( itr.toFirst(); itr.current(); ++itr )
00123         {
00124             if( !itr.current()->isEmpty() )
00125             {
00126                 painter->newPath();
00127                 painter->setRasterOp( Qt::XorROP );
00128                 painter->setPen( Qt::yellow );
00129                 painter->setBrush( Qt::NoBrush );
00130 
00131                 VSubpathIterator jtr( *( itr.current() ) );
00132                 for( ; jtr.current(); ++jtr )
00133                 {
00134                     jtr.current()->draw( painter );
00135                 }
00136 
00137                 painter->strokePath();
00138             }
00139         }
00140     }
00141     else if( state() != edit )
00142     {
00143         // paint fill:
00144         painter->newPath();
00145         painter->setFillRule( m_fillRule );
00146 
00147         for( itr.toFirst(); itr.current(); ++itr )
00148         {
00149             if( !itr.current()->isEmpty() )
00150             {
00151                 VSubpathIterator jtr( *( itr.current() ) );
00152                 for( ; jtr.current(); ++jtr )
00153                 {
00154                     jtr.current()->draw( painter );
00155                 }
00156             }
00157         }
00158 
00159         painter->setRasterOp( Qt::CopyROP );
00160         painter->setPen( Qt::NoPen );
00161         painter->setBrush( *fill() );
00162         painter->fillPath();
00163 
00164         // draw stroke:
00165         painter->setPen( *stroke() );
00166         painter->setBrush( Qt::NoBrush );
00167         painter->strokePath();
00168     }
00169 
00170     painter->restore();
00171 }
00172 
00173 const KoPoint&
00174 VPath::currentPoint() const
00175 {
00176     return m_paths.getLast()->currentPoint();
00177 }
00178 
00179 bool
00180 VPath::moveTo( const KoPoint& p )
00181 {
00182     // Append a new subpath if current subpath is not empty.
00183     if( !m_paths.getLast()->isEmpty() )
00184     {
00185         VSubpath* path = new VSubpath( this );
00186         m_paths.append( path );
00187     }
00188 
00189     return m_paths.getLast()->moveTo( p );
00190 }
00191 
00192 bool
00193 VPath::lineTo( const KoPoint& p )
00194 {
00195     return m_paths.getLast()->lineTo( p );
00196 }
00197 
00198 bool
00199 VPath::curveTo(
00200     const KoPoint& p1, const KoPoint& p2, const KoPoint& p3 )
00201 {
00202     return m_paths.getLast()->curveTo( p1, p2, p3 );
00203 }
00204 
00205 bool
00206 VPath::curve1To( const KoPoint& p2, const KoPoint& p3 )
00207 {
00208     return m_paths.getLast()->curve1To( p2, p3 );
00209 }
00210 
00211 bool
00212 VPath::curve2To( const KoPoint& p1, const KoPoint& p3 )
00213 {
00214     return m_paths.getLast()->curve2To( p1, p3 );
00215 }
00216 
00217 bool
00218 VPath::arcTo( const KoPoint& p1, const KoPoint& p2, const double r )
00219 {
00220     return m_paths.getLast()->arcTo( p1, p2, r );
00221 }
00222 
00223 void
00224 VPath::close()
00225 {
00226     m_paths.getLast()->close();
00227 
00228     // Append a new subpath.
00229     VSubpath* path = new VSubpath( this );
00230     path->moveTo( currentPoint() );
00231     m_paths.append( path );
00232 }
00233 
00234 bool
00235 VPath::isClosed() const
00236 {
00237     return m_paths.getLast()->isEmpty() || m_paths.getLast()->isClosed();
00238 }
00239 
00240 void
00241 VPath::combine( const VPath& composite )
00242 {
00243     VSubpathListIterator itr( composite.m_paths );
00244     for( ; itr.current(); ++itr )
00245     {
00246         combinePath( *( itr.current() ) );
00247     }
00248 }
00249 
00250 void
00251 VPath::combinePath( const VSubpath& path )
00252 {
00253     VSubpath* p = path.clone();
00254     p->setParent( this );
00255 
00256     // TODO: do complex inside tests instead:
00257     // Make new segments clock wise oriented:
00258 
00259     m_paths.append( p );
00260     m_fillRule = fillMode();
00261 }
00262 
00263 bool
00264 VPath::pointIsInside( const KoPoint& p ) const
00265 {
00266     // Check if point is inside boundingbox.
00267     if( !boundingBox().contains( p ) )
00268         return false;
00269 
00270 
00271     VSubpathListIterator itr( m_paths );
00272 
00273     for( itr.toFirst(); itr.current(); ++itr )
00274     {
00275         if( itr.current()->pointIsInside( p ) )
00276             return true;
00277     }
00278 
00279     return false;
00280 }
00281 
00282 bool
00283 VPath::intersects( const VSegment& segment ) const
00284 {
00285     // Check if boundingboxes intersect.
00286     if( !boundingBox().intersects( segment.boundingBox() ) )
00287         return false;
00288 
00289 
00290     VSubpathListIterator itr( m_paths );
00291 
00292     for( itr.toFirst(); itr.current(); ++itr )
00293     {
00294         if( itr.current()->intersects( segment ) )
00295             return true;
00296     }
00297 
00298     return false;
00299 }
00300 
00301 
00302 VFillRule
00303 VPath::fillMode() const
00304 {
00305     return ( m_paths.count() > 1 ) ? evenOdd : winding;
00306 }
00307 
00308 const KoRect&
00309 VPath::boundingBox() const
00310 {
00311     if( m_boundingBoxIsInvalid )
00312     {
00313         VSubpathListIterator itr( m_paths );
00314         itr.toFirst();
00315 
00316         m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect();
00317 
00318         for( ++itr; itr.current(); ++itr )
00319             m_boundingBox |= itr.current()->boundingBox();
00320 
00321         if( !m_boundingBox.isNull() )
00322         {
00323             // take line width into account:
00324             m_boundingBox.setCoords(
00325                 m_boundingBox.left()   - 0.5 * stroke()->lineWidth(),
00326                 m_boundingBox.top()    - 0.5 * stroke()->lineWidth(),
00327                 m_boundingBox.right()  + 0.5 * stroke()->lineWidth(),
00328                 m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() );
00329         }
00330         m_boundingBoxIsInvalid = false;
00331     }
00332 
00333     return m_boundingBox;
00334 }
00335 
00336 VPath*
00337 VPath::clone() const
00338 {
00339     return new VPath( *this );
00340 }
00341 
00342 void
00343 VPath::save( QDomElement& element ) const
00344 {
00345     if( state() != deleted )
00346     {
00347         QDomElement me = element.ownerDocument().createElement( "PATH" );
00348         element.appendChild( me );
00349 
00350         VObject::save( me );
00351 
00352         QString d;
00353         saveSvgPath( d );
00354         me.setAttribute( "d", d );
00355 
00356         //writeTransform( me );
00357 
00358         // save fill rule if necessary:
00359         if( !( m_fillRule == evenOdd ) )
00360             me.setAttribute( "fillRule", m_fillRule );
00361     }
00362 }
00363 
00364 void
00365 VPath::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const
00366 {
00367     if( state() != deleted )
00368     {
00369         docWriter->startElement( "draw:path" );
00370 
00371         QString d;
00372         saveSvgPath( d );
00373         docWriter->addAttribute( "svg:d", d );
00374 
00375         double x = boundingBox().x();
00376         double y = boundingBox().y();
00377         double w = boundingBox().width();
00378         double h = boundingBox().height();
00379 
00380         docWriter->addAttribute( "svg:viewBox", QString( "%1 %2 %3 %4" ).arg( x ).arg( y ).arg( w ).arg( h ) );
00381         docWriter->addAttributePt( "svg:x", x );
00382         docWriter->addAttributePt( "svg:y", y );
00383         docWriter->addAttributePt( "svg:width", w );
00384         docWriter->addAttributePt( "svg:height", h );
00385 
00386         VObject::saveOasis( store, docWriter, mainStyles, index );
00387 
00388         QWMatrix tmpMat;
00389         tmpMat.scale( 1, -1 );
00390         tmpMat.translate( 0, -document()->height() );
00391     
00392         QString transform = buildOasisTransform( tmpMat );
00393         if( !transform.isEmpty() )
00394             docWriter->addAttribute( "draw:transform", transform );
00395 
00396         docWriter->endElement();
00397     }
00398 }
00399 
00400 void
00401 VPath::saveOasisFill( KoGenStyles &mainStyles, KoGenStyle &stylesobjectauto ) const
00402 {
00403     if( m_fill )
00404     {
00405         QWMatrix mat;
00406         mat.scale( 1, -1 );
00407         mat.translate( 0, -document()->height() );
00408 
00409         // mirror fill before saving
00410         VFill fill( *m_fill );
00411         fill.transform( mat );
00412         fill.saveOasis( mainStyles, stylesobjectauto );
00413         // save fill rule if necessary:
00414         if( !( m_fillRule == evenOdd ) )
00415             stylesobjectauto.addProperty( "svg:fill-rule", "winding" );
00416     }
00417 }
00418 
00419 void
00420 VPath::transformByViewbox( const QDomElement &element, QString viewbox )
00421 {
00422     if( ! viewbox.isEmpty() )
00423     {
00424         // allow for viewbox def with ',' or whitespace
00425         QStringList points = QStringList::split( ' ', viewbox.replace( ',', ' ' ).simplifyWhiteSpace() );
00426 
00427         double w = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00428         double h = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00429         double x = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) );
00430         double y = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) );
00431 
00432         QWMatrix mat;
00433         mat.translate( x-KoUnit::parseValue( points[0] ), y-KoUnit::parseValue( points[1] ) );
00434         mat.scale( w / KoUnit::parseValue( points[2] ) , h / KoUnit::parseValue( points[3] ) );
00435         VTransformCmd cmd( 0L, mat );
00436         cmd.visitVPath( *this );
00437     }
00438 }
00439 
00440 bool
00441 VPath::loadOasis( const QDomElement &element, KoOasisLoadingContext &context )
00442 {
00443     setState( normal );
00444 
00445     QString viewbox;
00446 
00447     if( element.localName() == "path" )
00448     {
00449         QString data = element.attributeNS( KoXmlNS::svg, "d", QString::null );
00450         if( data.length() > 0 )
00451         {
00452             loadSvgPath( data );
00453         }
00454     
00455         m_fillRule = element.attributeNS( KoXmlNS::svg, "fill-rule", QString::null ) == "winding" ? winding : evenOdd;
00456 
00457         viewbox = element.attributeNS( KoXmlNS::svg, "viewBox", QString::null );
00458     }
00459     else if( element.localName() == "custom-shape" )
00460     {
00461         QDomNodeList list = element.childNodes();
00462         for( uint i = 0; i < list.count(); ++i )
00463         {
00464             if( list.item( i ).isElement() )
00465             {
00466                 QDomElement e = list.item( i ).toElement();
00467                 if( e.namespaceURI() != KoXmlNS::draw )
00468                     continue;
00469                 
00470                 if( e.localName() == "enhanced-geometry" )
00471                 {
00472                     QString data = e.attributeNS( KoXmlNS::draw, "enhanced-path", QString::null );
00473                     if( ! data.isEmpty() )
00474                         loadSvgPath( data );
00475 
00476                     viewbox = e.attributeNS( KoXmlNS::svg, "viewBox", QString::null );
00477                 }
00478             }
00479         }
00480     }
00481 
00482     transformByViewbox( element, viewbox );
00483 
00484     QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null );
00485     if( !trafo.isEmpty() )
00486         transformOasis( trafo );
00487 
00488     return VObject::loadOasis( element, context );
00489 }
00490 
00491 void
00492 VPath::load( const QDomElement& element )
00493 {
00494     setState( normal );
00495 
00496     VObject::load( element );
00497 
00498     QString data = element.attribute( "d" );
00499     if( data.length() > 0 )
00500     {
00501         loadSvgPath( data );
00502     }
00503     m_fillRule = element.attribute( "fillRule" ) == 0 ? evenOdd : winding;
00504     QDomNodeList list = element.childNodes();
00505     for( uint i = 0; i < list.count(); ++i )
00506     {
00507         if( list.item( i ).isElement() )
00508         {
00509             QDomElement child = list.item( i ).toElement();
00510 
00511             if( child.tagName() == "PATH" )
00512             {
00513                 VSubpath path( this );
00514                 path.load( child );
00515 
00516                 combinePath( path );
00517             }
00518             else
00519             {
00520                 VObject::load( child );
00521             }
00522         }
00523     }
00524 
00525     QString trafo = element.attribute( "transform" );
00526     if( !trafo.isEmpty() )
00527         transform( trafo );
00528 }
00529 
00530 void
00531 VPath::loadSvgPath( const QString &d )
00532 {
00533     //QTime s;s.start();
00534     parseSVG( d, true );
00535     //kdDebug(38000) << "Parsing time : " << s.elapsed() << endl;
00536 }
00537 
00538 void
00539 VPath::saveSvgPath( QString &d ) const
00540 {
00541     // save paths to svg:
00542     VSubpathListIterator itr( m_paths );
00543     for( itr.toFirst(); itr.current(); ++itr )
00544     {
00545         if( !itr.current()->isEmpty() )
00546             itr.current()->saveSvgPath( d );
00547     }
00548 }
00549 
00550 void
00551 VPath::svgMoveTo( double x1, double y1, bool )
00552 {
00553     moveTo( KoPoint( x1, y1 ) );
00554 }
00555 
00556 void
00557 VPath::svgLineTo( double x1, double y1, bool )
00558 {
00559     lineTo( KoPoint( x1, y1 ) );
00560 }
00561 
00562 void
00563 VPath::svgCurveToCubic( double x1, double y1, double x2, double y2, double x, double y, bool )
00564 {
00565     curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x, y ) );
00566 }
00567 
00568 void
00569 VPath::svgClosePath()
00570 {
00571     close();
00572 }
00573 
00574 void
00575 VPath::accept( VVisitor& visitor )
00576 {
00577     visitor.visitVPath( *this );
00578 }
00579 
00580 void
00581 VPath::transform( const QString &transform )
00582 {
00583     VTransformCmd cmd( 0L, parseTransform( transform ) );
00584     cmd.visitVPath( *this );
00585 }
00586 
00587 void
00588 VPath::transformOasis( const QString &transform )
00589 {
00590     VTransformCmd cmd( 0L, parseOasisTransform( transform ) );
00591     cmd.visitVPath( *this );
00592 }
00593 
00594 QWMatrix
00595 VPath::parseTransform( const QString &transform )
00596 {
00597     QWMatrix result;
00598 
00599     // Split string for handling 1 transform statement at a time
00600     QStringList subtransforms = QStringList::split(')', transform);
00601     QStringList::ConstIterator it = subtransforms.begin();
00602     QStringList::ConstIterator end = subtransforms.end();
00603     for(; it != end; ++it)
00604     {
00605         QStringList subtransform = QStringList::split('(', (*it));
00606 
00607         subtransform[0] = subtransform[0].stripWhiteSpace().lower();
00608         subtransform[1] = subtransform[1].simplifyWhiteSpace();
00609         QRegExp reg("[,( ]");
00610         QStringList params = QStringList::split(reg, subtransform[1]);
00611 
00612         if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
00613             subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
00614 
00615         if(subtransform[0] == "rotate")
00616         {
00617             if(params.count() == 3)
00618             {
00619                 double x = params[1].toDouble();
00620                 double y = params[2].toDouble();
00621 
00622                 result.translate(x, y);
00623                 result.rotate(params[0].toDouble());
00624                 result.translate(-x, -y);
00625             }
00626             else
00627                 result.rotate(params[0].toDouble());
00628         }
00629         else if(subtransform[0] == "translate")
00630         {
00631             if(params.count() == 2)
00632                 result.translate(params[0].toDouble(), params[1].toDouble());
00633             else    // Spec : if only one param given, assume 2nd param to be 0
00634                 result.translate(params[0].toDouble() , 0);
00635         }
00636         else if(subtransform[0] == "scale")
00637         {
00638             if(params.count() == 2)
00639                 result.scale(params[0].toDouble(), params[1].toDouble());
00640             else    // Spec : if only one param given, assume uniform scaling
00641                 result.scale(params[0].toDouble(), params[0].toDouble());
00642         }
00643         else if(subtransform[0] == "skewx")
00644             result.shear(tan(params[0].toDouble() * VGlobal::pi_180), 0.0F);
00645         else if(subtransform[0] == "skewy")
00646             result.shear(tan(params[0].toDouble() * VGlobal::pi_180), 0.0F);
00647         else if(subtransform[0] == "skewy")
00648             result.shear(0.0F, tan(params[0].toDouble() * VGlobal::pi_180));
00649         else if(subtransform[0] == "matrix")
00650         {
00651             if(params.count() >= 6)
00652                 result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble());
00653         }
00654     }
00655 
00656     return result;
00657 }
00658 
00659 QWMatrix
00660 VPath::parseOasisTransform( const QString &transform )
00661 {
00662     QWMatrix result;
00663 
00664     // Split string for handling 1 transform statement at a time
00665     QStringList subtransforms = QStringList::split(')', transform);
00666     QStringList::ConstIterator it = subtransforms.begin();
00667     QStringList::ConstIterator end = subtransforms.end();
00668     for(; it != end; ++it)
00669     {
00670         QStringList subtransform = QStringList::split('(', (*it));
00671 
00672         subtransform[0] = subtransform[0].stripWhiteSpace().lower();
00673         subtransform[1] = subtransform[1].simplifyWhiteSpace();
00674         QRegExp reg("[,( ]");
00675         QStringList params = QStringList::split(reg, subtransform[1]);
00676 
00677         if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
00678             subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
00679 
00680         if(subtransform[0] == "rotate")
00681         {
00682             // TODO find out what oo2 really does when rotating, it seems severly broken
00683             if(params.count() == 3)
00684             {
00685                 double x = KoUnit::parseValue( params[1] );
00686                 double y = KoUnit::parseValue( params[2] );
00687 
00688                 result.translate(x, y);
00689                 // oo2 rotates by radians
00690                 result.rotate( params[0].toDouble()*VGlobal::one_pi_180 );
00691                 result.translate(-x, -y);
00692             }
00693             else
00694             {
00695                 // oo2 rotates by radians
00696                 result.rotate( params[0].toDouble()*VGlobal::one_pi_180 );
00697             }
00698         }
00699         else if(subtransform[0] == "translate")
00700         {
00701             if(params.count() == 2)
00702             {
00703                 double x = KoUnit::parseValue( params[0] );
00704                 double y = KoUnit::parseValue( params[1] );
00705                 result.translate(x, y);
00706             }
00707             else    // Spec : if only one param given, assume 2nd param to be 0
00708                 result.translate( KoUnit::parseValue( params[0] ) , 0);
00709         }
00710         else if(subtransform[0] == "scale")
00711         {
00712             if(params.count() == 2)
00713                 result.scale(params[0].toDouble(), params[1].toDouble());
00714             else    // Spec : if only one param given, assume uniform scaling
00715                 result.scale(params[0].toDouble(), params[0].toDouble());
00716         }
00717         else if(subtransform[0] == "skewx")
00718             result.shear(tan(params[0].toDouble()), 0.0F);
00719         else if(subtransform[0] == "skewy")
00720             result.shear(tan(params[0].toDouble()), 0.0F);
00721         else if(subtransform[0] == "skewy")
00722             result.shear(0.0F, tan(params[0].toDouble()));
00723         else if(subtransform[0] == "matrix")
00724         {
00725             if(params.count() >= 6)
00726                 result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), KoUnit::parseValue( params[4] ), KoUnit::parseValue( params[5] ) );
00727         }
00728     }
00729 
00730     return result;
00731 }
00732 
00733 QString
00734 VPath::buildSvgTransform() const
00735 {
00736     return buildSvgTransform( m_matrix );
00737 }
00738 
00739 QString 
00740 VPath::buildSvgTransform( const QWMatrix &mat ) const
00741 {
00742     QString transform;
00743     if( !mat.isIdentity() )
00744     {
00745         transform = QString(  "matrix(%1, %2, %3, %4, %5, %6)" ).arg( mat.m11() )
00746                                                                 .arg( mat.m12() )
00747                                                                 .arg( mat.m21() )
00748                                                                 .arg( mat.m22() )
00749                                                                 .arg( mat.dx() )
00750                                                                 .arg( mat.dy() );
00751     }
00752     return transform;
00753 }
00754 
00755 QString
00756 VPath::buildOasisTransform() const
00757 {
00758     return buildSvgTransform( m_matrix );
00759 }
00760 
00761 QString 
00762 VPath::buildOasisTransform( const QWMatrix &mat ) const
00763 {
00764     QString transform;
00765     if( !mat.isIdentity() )
00766     {
00767         transform = QString(  "matrix(%1, %2, %3, %4, %5pt, %6pt)" ).arg( mat.m11() )
00768                                                                 .arg( mat.m12() )
00769                                                                 .arg( mat.m21() )
00770                                                                 .arg( mat.m22() )
00771                                                                 .arg( mat.dx() )
00772                                                                 .arg( mat.dy() );
00773     }
00774     return transform;
00775 }
KDE Home | KDE Accessibility Home | Description of Access Keys