24#include <tqvaluelist.h>
34class VSubpathIteratorList
37 VSubpathIteratorList()
38 : m_list( 0L ), m_iterator( 0L )
41 ~VSubpathIteratorList()
52 m_list->push_front( itr );
55 m_list =
new TQValueList<VSubpathIterator*>;
56 m_list->push_front( itr );
62 if( m_iterator == itr )
66 m_list->remove( itr );
68 if( m_list->isEmpty() )
76 void notifyClear(
bool zeroList )
81 m_iterator->m_list = 0L;
83 m_iterator->m_current = 0L;
89 TQValueList<VSubpathIterator*>::Iterator itr = m_list->begin();
94 ( *itr )->m_list = 0L;
96 ( *itr )->m_current = 0L;
105 if( m_iterator->m_current == segment )
106 m_iterator->m_current = current;
112 TQValueList<VSubpathIterator*>::Iterator itr = m_list->begin();
113 itr != m_list->end();
116 if( ( *itr )->m_current == segment )
117 ( *itr )->m_current = current;
123 TQValueList<VSubpathIterator*>* m_list;
128VSubpath::VSubpath(
VObject* parent )
133 m_first = m_last = m_current = 0L;
142VSubpath::VSubpath(
const VSubpath& list )
145 m_isClosed = list.isClosed();
147 m_first = m_last = m_current = 0L;
156 append( segment->
clone() );
157 segment = segment->m_next;
161VSubpath::VSubpath(
const VSegment& segment )
166 m_first = m_last = m_current = 0L;
182 append( segment.
clone() );
188 delete m_iteratorList;
192VSubpath::currentPoint()
const
194 return getLast()->
knot();
198VSubpath::moveTo(
const KoPoint& p )
211VSubpath::lineTo(
const KoPoint& p )
228 const KoPoint& p1,
const KoPoint& p2,
const KoPoint& p3 )
247VSubpath::curve1To(
const KoPoint& p2,
const KoPoint& p3 )
266VSubpath::curve2To(
const KoPoint& p1,
const KoPoint& p3 )
286 const KoPoint& p1,
const KoPoint& p2,
const double r )
307 if( isClosed() || r < 0.0 )
313 double dx0 = currentPoint().x() - p1.x();
314 double dy0 = currentPoint().y() - p1.y();
315 double dx2 = p2.x() - p1.x();
316 double dy2 = p2.y() - p1.y();
319 double dsqT10 = dx0 * dx0 + dy0 * dy0;
320 double dsqT12 = dx2 * dx2 + dy2 * dy2;
325 double num = dy0 * dx2 - dy2 * dx0;
327 double denom = sqrt( dsqT10 * dsqT12 ) - ( dx0 * dx2 + dy0 * dy2 );
330 if( 1.0 + denom == 1.0 )
338 double dP1B0 = fabs( r * num / denom );
341 KoPoint b0 = p1 + KoPoint( dx0, dy0 ) * ( dP1B0 / sqrt( dsqT10 ) );
344 if( !b0.isNear( currentPoint(), VGlobal::isNearRange ) )
348 KoPoint b3 = p1 + KoPoint( dx2, dy2 ) * ( dP1B0 / sqrt( dsqT12 ) );
353 const KoPoint d = p1 - b0;
355 double distsq = d * d;
362 if( distsq >= rsq * VGlobal::veryBigNumber )
369 fract = ( 4.0 / 3.0 ) / ( 1.0 + sqrt( 1.0 + distsq / rsq ) );
372 KoPoint b1 = b0 + ( p1 - b0 ) * fract;
373 KoPoint b2 = b3 + ( p1 - b3 ) * fract;
376 curveTo( b1, b2, b3 );
393 getLast()->
setKnot( getFirst()->knot() );
399 getLast()->knot().isNear(
400 getFirst()->knot(), VGlobal::isNearRange ) )
403 getLast()->
setKnot( getFirst()->knot() );
408 lineTo( getFirst()->knot() );
482 bool closed = isClosed() || getLast()->
knot() == getFirst()->
knot();
484 TQValueList<double> rparams;
495 for(
int i = 0; i <= segment->
degree(); ++i )
496 tmpCurve.current()->
setP(i, segment->
p(i)-p );
498 tmpCurve.current()->rootParams( rparams );
500 segment = segment->
next();
507 KoPoint prevKnot = getLast()->
knot() - p;
508 KoPoint nextKnot = getFirst()->
knot() - p;
510 double dx = nextKnot.x() - prevKnot.x();
511 double dy = nextKnot.y() - prevKnot.y();
514 rparams.append( nextKnot.x() );
518 if( ( prevKnot.y() < 0.0 && nextKnot.y() > 0.0 ) || ( prevKnot.y() > 0.0 && nextKnot.y() < 0.0 ) )
520 double n = prevKnot.y() - dy / dx * prevKnot.x();
521 rparams.append( -n * dx / dy );
526 kdDebug(38000) <<
"intersection count: " << rparams.count() << endl;
529 qHeapSort( rparams );
531 TQValueList<double>::iterator itr, etr = rparams.end();
533 for( itr = rparams.begin(); itr != etr; ++itr )
534 kdDebug(38000) <<
"intersection: " << *itr << endl;
539 for( itr = rparams.begin(); itr != etr; ++itr )
554 if ( rparams.front() < 0.0 && rparams.back() > 0.0 )
583 segment = segment->
next();
609 const VSegment* bottomRight = getFirst();
613 if( segment->
knot().y() < bottomRight->
knot().y() )
614 bottomRight = segment;
615 else if( segment->
knot().y() - bottomRight->
knot().y()
616 < VGlobal::isNearRange )
618 if( segment->
knot().x() > bottomRight->
knot().x() )
619 bottomRight = segment;
622 segment = segment->
next();
630 if( bottomRight == getFirst() )
633 current = bottomRight;
635 if( bottomRight == getLast() )
636 next = getFirst()->
next();
638 next = bottomRight->
next();
646 ( current->
knot().x() - current->
prev()->
knot().x() ) < 0.0;
658 list.moveTo( getLast()->knot() );
662 while( segment->
prev() )
664 list.append( segment->
revert() );
665 segment = segment->
prev();
668 list.m_isClosed = isClosed();
685 if( segment->
state() != VSegment::deleted )
688 segment = segment->m_next;
704VSubpath::saveSvgPath( TQString &d )
const
711 if( segment->
state() == VSegment::normal )
713 if( segment->
degree() <= 2 )
716 if( segment->
prev() )
718 d += TQString(
"L%1 %2" ).
719 arg( segment->
knot().x() ).arg( segment->
knot().y() );
724 d += TQString(
"M%1 %2" ).
725 arg( segment->
knot().x() ).arg( segment->
knot().y() );
732 d += TQString(
"C%1 %2 %3 %4 %5 %6" ).
733 arg( segment->
point( segment->
degree() - 3 ).x() ).
734 arg( segment->
point( segment->
degree() - 3 ).y() ).
735 arg( segment->
point( segment->
degree() - 2 ).x() ).
736 arg( segment->
point( segment->
degree() - 2 ).y() ).
737 arg( segment->
knot().x() ).
738 arg( segment->
knot().y() );
742 segment = segment->m_next;
756 TQDomNodeList list = element.childNodes();
758 for( uint i = 0; i < list.count(); ++i )
760 if( list.item( i ).isElement() )
762 TQDomElement segment = list.item( i ).toElement();
770 if( element.attribute(
"isClosed" ) == 0 ?
false : true )
782VSubpath::operator=(
const VSubpath& list )
787 m_isClosed = list.isClosed();
795 append( segment->
clone() );
796 segment = segment->m_next;
806VSubpath::insert(
const VSegment* segment )
808 if( m_currentIndex == -1 )
815 m_current->m_prev = s;
818 s->m_next = m_current;
829VSubpath::insert( uint index,
const VSegment* segment )
838 else if( index == m_number )
865VSubpath::prepend(
const VSegment* segment )
871 if( ( s->m_next = m_first ) )
876 m_first = m_current = s;
885VSubpath::append(
const VSegment* segment )
891 if( ( s->m_prev = m_last ) )
896 m_last = m_current = s;
898 m_currentIndex = m_number;
909 m_first = m_last = m_current = 0L;
914 m_iteratorList->notifyClear(
false );
921 segment = segment->m_next;
936 return m_current = m_first;
947 m_currentIndex = m_number - 1;
948 return m_current = m_last;
959 if( m_current->m_prev )
962 return m_current = m_current->m_prev;
977 if( m_current->m_next )
980 return m_current = m_current->m_next;
991VSubpath::locate( uint index )
993 if( index ==
static_cast<uint
>( m_currentIndex ) )
996 if( !m_current && m_first )
1003 int distance = index - m_currentIndex;
1006 if( index >= m_number )
1010 distance = -distance;
1013 static_cast<uint
>( distance ) < index &&
1014 static_cast<uint
>( distance ) < m_number - index )
1016 segment = m_current;
1017 forward = index >
static_cast<uint
>( m_currentIndex );
1019 else if( index < m_number - index )
1028 distance = m_number - index - 1;
1037 segment = segment->m_next;
1042 segment = segment->m_prev;
1045 m_currentIndex = index;
1046 return m_current = segment;
1050VSubpathIterator::VSubpathIterator(
const VSubpath& list )
1052 m_list =
const_cast<VSubpath*
>( &list );
1053 m_current = m_list->m_first;
1055 if( !m_list->m_iteratorList )
1056 m_list->m_iteratorList =
new VSubpathIteratorList();
1058 m_list->m_iteratorList->add(
this );
1063 m_list = itr.m_list;
1064 m_current = itr.m_current;
1067 m_list->m_iteratorList->add(
this );
1070VSubpathIterator::~VSubpathIterator()
1073 m_list->m_iteratorList->remove(
this );
1080 m_list->m_iteratorList->remove(
this );
1082 m_list = itr.m_list;
1083 m_current = itr.m_current;
1086 m_list->m_iteratorList->add(
this );
1092VSubpathIterator::current()
const
1098 m_current->
state() == VSegment::deleted )
1100 return m_current->
next();
1107VSubpathIterator::operator()()
1109 if(
VSegment*
const old = current() )
1111 m_current = current()->
next();
1119VSubpathIterator::operator++()
1122 return m_current = current()->
next();
1128VSubpathIterator::operator+=( uint i )
1130 while( current() && i-- )
1131 m_current = current()->
next();
1137VSubpathIterator::operator--()
1140 return m_current = current()->
prev();
1146VSubpathIterator::operator-=( uint i )
1148 while( current() && i-- )
1149 m_current = current()->
prev();
The base class for all karbon objects.
bool m_boundingBoxIsInvalid
the flag stating if the bounding box is valid
VObject * parent() const
Returns pointer to current parent object.
void invalidateBoundingBox()
Invalidates the bounding box, so it has to be recalculated.
KoRect m_boundingBox
the object's bounding box
A class representing lines and beziers.
VSegment * next() const
Returns a pointer to the next not deleted segment, if stored in a VSubpath.
VSegment * clone() const
Returns a pointer to a copy of this segment.
void setDegree(unsigned short deg)
Sets the segment's degree and thus resizes the array of node data.
void setKnot(const KoPoint &p)
Sets the knot.
void setPoint(int i, const KoPoint &p)
Sets the segment's point with index 0 <= i < degree() to "p".
bool intersects(const VSegment &segment) const
Returns true, if this segment intersects the other segment.
const KoPoint & p(int i) const
This is a convenience function.
VSegment * prev() const
Returns a pointer to the previous not deleted segment, if stored in a VSubpath.
unsigned short degree() const
Returns the segment's degree, which is identical to the number of nodes.
const KoPoint & point(int i) const
Returns the segment's point with index 0 <= i < degree().
const KoPoint & knot() const
Returns the knot.
VSegment * revert() const
Creates a reverted version of this segment.
VState state() const
Returns the segment state.
KoRect boundingBox() const
Calculates the bounding box.
void setP(int i, const KoPoint &p)
This is a convenience function.
VSubpathIterator provides an iterator class for highlevel path access.
VSubpath provides a sophisticated list of VSegment.
bool counterClockwise() const
Returns false if segmentlist is oriented clockwise.
virtual void accept(VVisitor &visitor)
Accept a VVisitor.
void revert()
Reverts the winding orientation.
virtual VSubpath * clone() const
Create an exact copy of this object.
bool pointIsInside(const KoPoint &p) const
Returns true if point p is located inside the path.
bool isEmpty() const
Returns true if the current path is "emtpy".
bool intersects(const VSegment &segment) const
Returns true if the segment intersects this path.
virtual const KoRect & boundingBox() const
Calculates the tightest bounding box around the object.
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
The abstract visitor class.
virtual void visitVSubpath(VSubpath &path)
Visit method for a VSubpath.