karbon

vcomposite.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001, 2002, 2003 The Karbon Developers
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <tqdom.h>
21#include <tqpainter.h>
22#include <tqwmatrix.h>
23#include <tqregexp.h>
24
25#include <KoPoint.h>
26#include <KoRect.h>
27#include <KoUnit.h>
28#include <KoStore.h>
29#include <KoXmlWriter.h>
30#include <KoXmlNS.h>
31#include <KoGenStyles.h>
32
33#include "vcomposite.h"
34#include "vcomposite_iface.h"
35#include "vfill.h"
36#include "vpainter.h"
37#include "vsegment.h"
38#include "vstroke.h"
39#include "vvisitor.h"
40#include "vpath.h"
41#include "commands/vtransformcmd.h"
42#include "vdocument.h"
43
44#include <kdebug.h>
45
46
47VPath::VPath( VObject* parent, VState state )
48 : VObject( parent, state ), m_fillRule( winding )
49{
50 m_paths.setAutoDelete( true );
51
52 // add an initial path:
53 m_paths.append( new VSubpath( this ) );
54
55 // we need a stroke for boundingBox() at anytime:
56 m_stroke = new VStroke( this );
57 m_fill = new VFill();
58
59 m_drawCenterNode = false;
60}
61
62VPath::VPath( const VPath& composite )
63 : VObject( composite ), SVGPathParser()
64{
65 m_paths.setAutoDelete( true );
66
67 VSubpath* path;
68
69 VSubpathListIterator itr( composite.m_paths );
70 for( itr.toFirst(); itr.current(); ++itr )
71 {
72 path = itr.current()->clone();
73 path->setParent( this );
74 m_paths.append( path );
75 }
76
77 if ( composite.stroke() )
78 setStroke( *composite.stroke() );
79
80 if ( composite.fill() )
81 setFill( *composite.fill() );
82
83 m_drawCenterNode = false;
84 m_fillRule = composite.m_fillRule;
85 m_matrix = composite.m_matrix;
86}
87
88VPath::~VPath()
89{
90}
91
92DCOPObject* VPath::dcopObject()
93{
94 if ( !m_dcop )
95 m_dcop = new VPathIface( this );
96
97 return m_dcop;
98}
99
100
101void
102VPath::draw( VPainter* painter, const KoRect *rect ) const
103{
104 if(
105 state() == deleted ||
106 state() == hidden ||
107 state() == hidden_locked )
108 {
109 return;
110 }
111
112 if( rect && !rect->intersects( boundingBox() ) )
113 return;
114
115 painter->save();
116
117 VSubpathListIterator itr( m_paths );
118
119 // draw simplistic contour:
120 if( state() == edit )
121 {
122 for( itr.toFirst(); itr.current(); ++itr )
123 {
124 if( !itr.current()->isEmpty() )
125 {
126 painter->newPath();
127 painter->setRasterOp( TQt::XorROP );
128 painter->setPen( TQt::yellow );
129 painter->setBrush( TQt::NoBrush );
130
131 VSubpathIterator jtr( *( itr.current() ) );
132 for( ; jtr.current(); ++jtr )
133 {
134 jtr.current()->draw( painter );
135 }
136
137 painter->strokePath();
138 }
139 }
140 }
141 else if( state() != edit )
142 {
143 // paint fill:
144 painter->newPath();
145 painter->setFillRule( m_fillRule );
146
147 for( itr.toFirst(); itr.current(); ++itr )
148 {
149 if( !itr.current()->isEmpty() )
150 {
151 VSubpathIterator jtr( *( itr.current() ) );
152 for( ; jtr.current(); ++jtr )
153 {
154 jtr.current()->draw( painter );
155 }
156 }
157 }
158
159 painter->setRasterOp( TQt::CopyROP );
160 painter->setPen( TQt::NoPen );
161 painter->setBrush( *fill() );
162 painter->fillPath();
163
164 // draw stroke:
165 painter->setPen( *stroke() );
166 painter->setBrush( TQt::NoBrush );
167 painter->strokePath();
168 }
169
170 painter->restore();
171}
172
173const KoPoint&
175{
176 return m_paths.getLast()->currentPoint();
177}
178
179bool
180VPath::moveTo( const KoPoint& p )
181{
182 // Append a new subpath if current subpath is not empty.
183 if( !m_paths.getLast()->isEmpty() )
184 {
185 VSubpath* path = new VSubpath( this );
186 m_paths.append( path );
187 }
188
189 return m_paths.getLast()->moveTo( p );
190}
191
192bool
193VPath::lineTo( const KoPoint& p )
194{
195 return m_paths.getLast()->lineTo( p );
196}
197
198bool
199VPath::curveTo(
200 const KoPoint& p1, const KoPoint& p2, const KoPoint& p3 )
201{
202 return m_paths.getLast()->curveTo( p1, p2, p3 );
203}
204
205bool
206VPath::curve1To( const KoPoint& p2, const KoPoint& p3 )
207{
208 return m_paths.getLast()->curve1To( p2, p3 );
209}
210
211bool
212VPath::curve2To( const KoPoint& p1, const KoPoint& p3 )
213{
214 return m_paths.getLast()->curve2To( p1, p3 );
215}
216
217bool
218VPath::arcTo( const KoPoint& p1, const KoPoint& p2, const double r )
219{
220 return m_paths.getLast()->arcTo( p1, p2, r );
221}
222
223void
225{
226 m_paths.getLast()->close();
227
228 // Append a new subpath.
229 VSubpath* path = new VSubpath( this );
230 path->moveTo( currentPoint() );
231 m_paths.append( path );
232}
233
234bool
235VPath::isClosed() const
236{
237 return m_paths.getLast()->isEmpty() || m_paths.getLast()->isClosed();
238}
239
240void
241VPath::combine( const VPath& composite )
242{
243 VSubpathListIterator itr( composite.m_paths );
244 for( ; itr.current(); ++itr )
245 {
246 combinePath( *( itr.current() ) );
247 }
248}
249
250void
252{
253 VSubpath* p = path.clone();
254 p->setParent( this );
255
256 // TODO: do complex inside tests instead:
257 // Make new segments clock wise oriented:
258
259 m_paths.append( p );
260 m_fillRule = fillMode();
261}
262
263bool
264VPath::pointIsInside( const KoPoint& p ) const
265{
266 // Check if point is inside boundingbox.
267 if( !boundingBox().contains( p ) )
268 return false;
269
270
271 VSubpathListIterator itr( m_paths );
272
273 for( itr.toFirst(); itr.current(); ++itr )
274 {
275 if( itr.current()->pointIsInside( p ) )
276 return true;
277 }
278
279 return false;
280}
281
282bool
283VPath::intersects( const VSegment& segment ) const
284{
285 // Check if boundingboxes intersect.
286 if( !boundingBox().intersects( segment.boundingBox() ) )
287 return false;
288
289
290 VSubpathListIterator itr( m_paths );
291
292 for( itr.toFirst(); itr.current(); ++itr )
293 {
294 if( itr.current()->intersects( segment ) )
295 return true;
296 }
297
298 return false;
299}
300
301
302VFillRule
303VPath::fillMode() const
304{
305 return ( m_paths.count() > 1 ) ? evenOdd : winding;
306}
307
308const KoRect&
310{
312 {
313 VSubpathListIterator itr( m_paths );
314 itr.toFirst();
315
316 m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect();
317
318 for( ++itr; itr.current(); ++itr )
319 m_boundingBox |= itr.current()->boundingBox();
320
321 if( !m_boundingBox.isNull() )
322 {
323 // take line width into account:
324 m_boundingBox.setCoords(
325 m_boundingBox.left() - 0.5 * stroke()->lineWidth(),
326 m_boundingBox.top() - 0.5 * stroke()->lineWidth(),
327 m_boundingBox.right() + 0.5 * stroke()->lineWidth(),
328 m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() );
329 }
331 }
332
333 return m_boundingBox;
334}
335
336VPath*
338{
339 return new VPath( *this );
340}
341
342void
343VPath::save( TQDomElement& element ) const
344{
345 if( state() != deleted )
346 {
347 TQDomElement me = element.ownerDocument().createElement( "PATH" );
348 element.appendChild( me );
349
350 VObject::save( me );
351
352 TQString d;
353 saveSvgPath( d );
354 me.setAttribute( "d", d );
355
356 //writeTransform( me );
357
358 // save fill rule if necessary:
359 if( !( m_fillRule == evenOdd ) )
360 me.setAttribute( "fillRule", m_fillRule );
361 }
362}
363
364void
365VPath::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const
366{
367 if( state() != deleted )
368 {
369 docWriter->startElement( "draw:path" );
370
371 TQString d;
372 saveSvgPath( d );
373 docWriter->addAttribute( "svg:d", d );
374
375 double x = boundingBox().x();
376 double y = boundingBox().y();
377 double w = boundingBox().width();
378 double h = boundingBox().height();
379
380 docWriter->addAttribute( "svg:viewBox", TQString( "%1 %2 %3 %4" ).arg( x ).arg( y ).arg( w ).arg( h ) );
381 docWriter->addAttributePt( "svg:x", x );
382 docWriter->addAttributePt( "svg:y", y );
383 docWriter->addAttributePt( "svg:width", w );
384 docWriter->addAttributePt( "svg:height", h );
385
386 VObject::saveOasis( store, docWriter, mainStyles, index );
387
388 TQWMatrix tmpMat;
389 tmpMat.scale( 1, -1 );
390 tmpMat.translate( 0, -document()->height() );
391
392 TQString transform = buildOasisTransform( tmpMat );
393 if( !transform.isEmpty() )
394 docWriter->addAttribute( "draw:transform", transform );
395
396 docWriter->endElement();
397 }
398}
399
400void
401VPath::saveOasisFill( KoGenStyles &mainStyles, KoGenStyle &stylesobjectauto ) const
402{
403 if( m_fill )
404 {
405 TQWMatrix mat;
406 mat.scale( 1, -1 );
407 mat.translate( 0, -document()->height() );
408
409 // mirror fill before saving
410 VFill fill( *m_fill );
411 fill.transform( mat );
412 fill.saveOasis( mainStyles, stylesobjectauto );
413 // save fill rule if necessary:
414 if( !( m_fillRule == evenOdd ) )
415 stylesobjectauto.addProperty( "svg:fill-rule", "winding" );
416 }
417}
418
419void
420VPath::transformByViewbox( const TQDomElement &element, TQString viewbox )
421{
422 if( ! viewbox.isEmpty() )
423 {
424 // allow for viewbox def with ',' or whitespace
425 TQStringList points = TQStringList::split( ' ', viewbox.replace( ',', ' ' ).simplifyWhiteSpace() );
426
427 double w = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", TQString() ) );
428 double h = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", TQString() ) );
429 double x = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", TQString() ) );
430 double y = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", TQString() ) );
431
432 TQWMatrix mat;
433 mat.translate( x-KoUnit::parseValue( points[0] ), y-KoUnit::parseValue( points[1] ) );
434 mat.scale( w / KoUnit::parseValue( points[2] ) , h / KoUnit::parseValue( points[3] ) );
435 VTransformCmd cmd( 0L, mat );
436 cmd.visitVPath( *this );
437 }
438}
439
440bool
441VPath::loadOasis( const TQDomElement &element, KoOasisLoadingContext &context )
442{
443 setState( normal );
444
445 TQString viewbox;
446
447 if( element.localName() == "path" )
448 {
449 TQString data = element.attributeNS( KoXmlNS::svg, "d", TQString() );
450 if( data.length() > 0 )
451 {
452 loadSvgPath( data );
453 }
454
455 m_fillRule = element.attributeNS( KoXmlNS::svg, "fill-rule", TQString() ) == "winding" ? winding : evenOdd;
456
457 viewbox = element.attributeNS( KoXmlNS::svg, "viewBox", TQString() );
458 }
459 else if( element.localName() == "custom-shape" )
460 {
461 TQDomNodeList list = element.childNodes();
462 for( uint i = 0; i < list.count(); ++i )
463 {
464 if( list.item( i ).isElement() )
465 {
466 TQDomElement e = list.item( i ).toElement();
467 if( e.namespaceURI() != KoXmlNS::draw )
468 continue;
469
470 if( e.localName() == "enhanced-geometry" )
471 {
472 TQString data = e.attributeNS( KoXmlNS::draw, "enhanced-path", TQString() );
473 if( ! data.isEmpty() )
474 loadSvgPath( data );
475
476 viewbox = e.attributeNS( KoXmlNS::svg, "viewBox", TQString() );
477 }
478 }
479 }
480 }
481
482 transformByViewbox( element, viewbox );
483
484 TQString trafo = element.attributeNS( KoXmlNS::draw, "transform", TQString() );
485 if( !trafo.isEmpty() )
486 transformOasis( trafo );
487
488 return VObject::loadOasis( element, context );
489}
490
491void
492VPath::load( const TQDomElement& element )
493{
494 setState( normal );
495
496 VObject::load( element );
497
498 TQString data = element.attribute( "d" );
499 if( data.length() > 0 )
500 {
501 loadSvgPath( data );
502 }
503 m_fillRule = element.attribute( "fillRule" ) == 0 ? evenOdd : winding;
504 TQDomNodeList list = element.childNodes();
505 for( uint i = 0; i < list.count(); ++i )
506 {
507 if( list.item( i ).isElement() )
508 {
509 TQDomElement child = list.item( i ).toElement();
510
511 if( child.tagName() == "PATH" )
512 {
513 VSubpath path( this );
514 path.load( child );
515
516 combinePath( path );
517 }
518 else
519 {
520 VObject::load( child );
521 }
522 }
523 }
524
525 TQString trafo = element.attribute( "transform" );
526 if( !trafo.isEmpty() )
527 transform( trafo );
528}
529
530void
531VPath::loadSvgPath( const TQString &d )
532{
533 //TQTime s;s.start();
534 parseSVG( d, true );
535 //kdDebug(38000) << "Parsing time : " << s.elapsed() << endl;
536}
537
538void
539VPath::saveSvgPath( TQString &d ) const
540{
541 // save paths to svg:
542 VSubpathListIterator itr( m_paths );
543 for( itr.toFirst(); itr.current(); ++itr )
544 {
545 if( !itr.current()->isEmpty() )
546 itr.current()->saveSvgPath( d );
547 }
548}
549
550void
551VPath::svgMoveTo( double x1, double y1, bool )
552{
553 moveTo( KoPoint( x1, y1 ) );
554}
555
556void
557VPath::svgLineTo( double x1, double y1, bool )
558{
559 lineTo( KoPoint( x1, y1 ) );
560}
561
562void
563VPath::svgCurveToCubic( double x1, double y1, double x2, double y2, double x, double y, bool )
564{
565 curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x, y ) );
566}
567
568void
569VPath::svgClosePath()
570{
571 close();
572}
573
574void
576{
577 visitor.visitVPath( *this );
578}
579
580void
581VPath::transform( const TQString &transform )
582{
583 VTransformCmd cmd( 0L, parseTransform( transform ) );
584 cmd.visitVPath( *this );
585}
586
587void
588VPath::transformOasis( const TQString &transform )
589{
590 VTransformCmd cmd( 0L, parseOasisTransform( transform ) );
591 cmd.visitVPath( *this );
592}
593
594TQWMatrix
595VPath::parseTransform( const TQString &transform )
596{
597 TQWMatrix result;
598
599 // Split string for handling 1 transform statement at a time
600 TQStringList subtransforms = TQStringList::split(')', transform);
601 TQStringList::ConstIterator it = subtransforms.begin();
602 TQStringList::ConstIterator end = subtransforms.end();
603 for(; it != end; ++it)
604 {
605 TQStringList subtransform = TQStringList::split('(', (*it));
606
607 subtransform[0] = subtransform[0].stripWhiteSpace().lower();
608 subtransform[1] = subtransform[1].simplifyWhiteSpace();
609 TQRegExp reg("[,( ]");
610 TQStringList params = TQStringList::split(reg, subtransform[1]);
611
612 if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
613 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
614
615 if(subtransform[0] == "rotate")
616 {
617 if(params.count() == 3)
618 {
619 double x = params[1].toDouble();
620 double y = params[2].toDouble();
621
622 result.translate(x, y);
623 result.rotate(params[0].toDouble());
624 result.translate(-x, -y);
625 }
626 else
627 result.rotate(params[0].toDouble());
628 }
629 else if(subtransform[0] == "translate")
630 {
631 if(params.count() == 2)
632 result.translate(params[0].toDouble(), params[1].toDouble());
633 else // Spec : if only one param given, assume 2nd param to be 0
634 result.translate(params[0].toDouble() , 0);
635 }
636 else if(subtransform[0] == "scale")
637 {
638 if(params.count() == 2)
639 result.scale(params[0].toDouble(), params[1].toDouble());
640 else // Spec : if only one param given, assume uniform scaling
641 result.scale(params[0].toDouble(), params[0].toDouble());
642 }
643 else if(subtransform[0] == "skewx")
644 result.shear(tan(params[0].toDouble() * VGlobal::pi_180), 0.0F);
645 else if(subtransform[0] == "skewy")
646 result.shear(tan(params[0].toDouble() * VGlobal::pi_180), 0.0F);
647 else if(subtransform[0] == "skewy")
648 result.shear(0.0F, tan(params[0].toDouble() * VGlobal::pi_180));
649 else if(subtransform[0] == "matrix")
650 {
651 if(params.count() >= 6)
652 result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), params[5].toDouble());
653 }
654 }
655
656 return result;
657}
658
659TQWMatrix
660VPath::parseOasisTransform( const TQString &transform )
661{
662 TQWMatrix result;
663
664 // Split string for handling 1 transform statement at a time
665 TQStringList subtransforms = TQStringList::split(')', transform);
666 TQStringList::ConstIterator it = subtransforms.begin();
667 TQStringList::ConstIterator end = subtransforms.end();
668 for(; it != end; ++it)
669 {
670 TQStringList subtransform = TQStringList::split('(', (*it));
671
672 subtransform[0] = subtransform[0].stripWhiteSpace().lower();
673 subtransform[1] = subtransform[1].simplifyWhiteSpace();
674 TQRegExp reg("[,( ]");
675 TQStringList params = TQStringList::split(reg, subtransform[1]);
676
677 if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
678 subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
679
680 if(subtransform[0] == "rotate")
681 {
682 // TODO find out what oo2 really does when rotating, it seems severly broken
683 if(params.count() == 3)
684 {
685 double x = KoUnit::parseValue( params[1] );
686 double y = KoUnit::parseValue( params[2] );
687
688 result.translate(x, y);
689 // oo2 rotates by radians
690 result.rotate( params[0].toDouble()*VGlobal::one_pi_180 );
691 result.translate(-x, -y);
692 }
693 else
694 {
695 // oo2 rotates by radians
696 result.rotate( params[0].toDouble()*VGlobal::one_pi_180 );
697 }
698 }
699 else if(subtransform[0] == "translate")
700 {
701 if(params.count() == 2)
702 {
703 double x = KoUnit::parseValue( params[0] );
704 double y = KoUnit::parseValue( params[1] );
705 result.translate(x, y);
706 }
707 else // Spec : if only one param given, assume 2nd param to be 0
708 result.translate( KoUnit::parseValue( params[0] ) , 0);
709 }
710 else if(subtransform[0] == "scale")
711 {
712 if(params.count() == 2)
713 result.scale(params[0].toDouble(), params[1].toDouble());
714 else // Spec : if only one param given, assume uniform scaling
715 result.scale(params[0].toDouble(), params[0].toDouble());
716 }
717 else if(subtransform[0] == "skewx")
718 result.shear(tan(params[0].toDouble()), 0.0F);
719 else if(subtransform[0] == "skewy")
720 result.shear(tan(params[0].toDouble()), 0.0F);
721 else if(subtransform[0] == "skewy")
722 result.shear(0.0F, tan(params[0].toDouble()));
723 else if(subtransform[0] == "matrix")
724 {
725 if(params.count() >= 6)
726 result.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(), KoUnit::parseValue( params[4] ), KoUnit::parseValue( params[5] ) );
727 }
728 }
729
730 return result;
731}
732
733TQString
734VPath::buildSvgTransform() const
735{
736 return buildSvgTransform( m_matrix );
737}
738
739TQString
740VPath::buildSvgTransform( const TQWMatrix &mat ) const
741{
742 TQString transform;
743 if( !mat.isIdentity() )
744 {
745 transform = TQString( "matrix(%1, %2, %3, %4, %5, %6)" ).arg( mat.m11() )
746 .arg( mat.m12() )
747 .arg( mat.m21() )
748 .arg( mat.m22() )
749 .arg( mat.dx() )
750 .arg( mat.dy() );
751 }
752 return transform;
753}
754
755TQString
756VPath::buildOasisTransform() const
757{
758 return buildSvgTransform( m_matrix );
759}
760
761TQString
762VPath::buildOasisTransform( const TQWMatrix &mat ) const
763{
764 TQString transform;
765 if( !mat.isIdentity() )
766 {
767 transform = TQString( "matrix(%1, %2, %3, %4, %5pt, %6pt)" ).arg( mat.m11() )
768 .arg( mat.m12() )
769 .arg( mat.m21() )
770 .arg( mat.m22() )
771 .arg( mat.dx() )
772 .arg( mat.dy() );
773 }
774 return transform;
775}
Manages the fill of shapes.
Definition vfill.h:45
The base class for all karbon objects.
Definition vobject.h:50
bool m_boundingBoxIsInvalid
the flag stating if the bounding box is valid
Definition vobject.h:287
DCOPObject * m_dcop
the object's DCOP object
Definition vobject.h:292
virtual void setState(const VState state)
Sets the state to a specified new state.
Definition vobject.h:163
virtual void saveOasis(KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index) const
Save this object's state to OpenDocument.
Definition vobject.cpp:116
@ hidden_locked
hidden and locked (r/o)
Definition vobject.h:57
@ deleted
deleted, nearly dead
Definition vobject.h:58
@ normal
visible, not active
Definition vobject.h:54
@ edit
visible, active and is currently manipulated by a tool
Definition vobject.h:62
@ hidden
hidden
Definition vobject.h:56
void setParent(VObject *parent)
Sets a new parent object.
Definition vobject.h:140
VFill * m_fill
the object's fill
Definition vobject.h:290
virtual VFill * fill() const
Gets the object's actual fill.
Definition vobject.h:177
KoRect m_boundingBox
the object's bounding box
Definition vobject.h:285
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
Definition vobject.cpp:157
virtual VStroke * stroke() const
Gets the object's actual stroke.
Definition vobject.h:170
virtual void save(TQDomElement &element) const
Save this object's state to xml.
Definition vobject.cpp:102
VDocument * document() const
Return document the object belongs to.
Definition vobject.cpp:216
virtual bool loadOasis(const TQDomElement &element, KoOasisLoadingContext &context)
Load this object's state from OpenDocument and initialize this object accordingly.
Definition vobject.cpp:181
VState state() const
Get the state the object is in.
Definition vobject.h:154
A composite path consists of one or many subpaths.
Definition vcomposite.h:48
virtual bool loadOasis(const TQDomElement &element, KoOasisLoadingContext &context)
Load this object's state from OpenDocument and initialize this object accordingly.
virtual void saveOasis(KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index) const
Save this object's state to OpenDocument.
const KoPoint & currentPoint() const
Returns the knot of the last segment of the last subpath.
virtual void draw(VPainter *painter, const KoRect *rect=0L) const
Draw the object to a painting device.
void close()
Closes the current subpath.
virtual void accept(VVisitor &visitor)
Accept a VVisitor.
void combine(const VPath &path)
Combines two composite paths.
bool arcTo(const KoPoint &p1, const KoPoint &p2, double r)
A convenience function to aproximate a circular arc with a bezier curve.
void combinePath(const VSubpath &path)
Adds a path to the composite path.
bool pointIsInside(const KoPoint &p) const
Returns true if point p is located inside the composite.
bool intersects(const VSegment &segment) const
Returns true if the segment intersects this composite.
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
virtual void save(TQDomElement &element) const
Save this object's state to xml.
virtual const KoRect & boundingBox() const
Calculates the tightest bounding box around the object.
virtual VPath * clone() const
Create an exact copy of this object.
virtual void svgMoveTo(double x1, double y1, bool abs=true)
For svg path data parsing.
virtual DCOPObject * dcopObject()
Returns pointer to internal DCOP object.
A class representing lines and beziers.
Definition vsegment.h:43
VSegment * clone() const
Returns a pointer to a copy of this segment.
KoRect boundingBox() const
Calculates the bounding box.
Definition vsegment.cpp:724
Manages stroke properties.
Definition vstroke.h:49
VSubpathIterator provides an iterator class for highlevel path access.
Definition vpath.h:180
VSubpath provides a sophisticated list of VSegment.
Definition vpath.h:43
virtual VSubpath * clone() const
Create an exact copy of this object.
Definition vpath.cpp:698
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
Definition vpath.cpp:751
The abstract visitor class.
Definition vvisitor.h:51
virtual void visitVPath(VPath &composite)
Visit method for a VPath.
Definition vvisitor.cpp:74