30VSegment::VSegment(
unsigned short deg )
34 m_nodes =
new VNodeData[
degree() ];
36 for(
unsigned short i = 0; i <
degree(); ++i )
45VSegment::VSegment(
const VSegment& segment )
47 m_degree = segment.
degree();
49 m_nodes =
new VNodeData[
degree() ];
51 m_state = segment.m_state;
55 m_prev = segment.m_prev;
56 m_next = segment.m_next;
59 for(
unsigned short i = 0; i <
degree(); i++ )
81 VNodeData* oldNodes = m_nodes;
82 KoPoint oldKnot =
knot();
85 m_nodes =
new VNodeData[ deg ];
88 m_nodes[ 0 ].m_vector = oldKnot;
92 unsigned short offset = kMax( 0, deg - m_degree );
94 for(
unsigned short i = offset; i < deg; ++i )
96 m_nodes[ i ].m_vector = oldNodes[ i - offset ].m_vector;
100 for(
unsigned short i = 0; i < offset; ++i )
102 m_nodes[ i ].m_vector = KoPoint( 0.0, 0.0 );
110 delete[]( oldNodes );
114VSegment::draw( VPainter* painter )
const
117 if(
state() == deleted )
129 painter->lineTo(
knot() );
134 painter->moveTo(
knot() );
151 for(
unsigned short i = 0; i <
degree() - 1; ++i )
176 KoPoint* d1, KoPoint* d2 )
const
194 *d2 = KoPoint( 0.0, 0.0 );
203 KoPoint* q =
new KoPoint[
degree() + 1 ];
207 for(
unsigned short i = 0; i <
degree(); ++i )
209 q[ i + 1 ] =
point( i );
214 for(
unsigned short j = 1; j <=
degree(); j++ )
216 for(
unsigned short i = 0; i <=
degree() - j; i++ )
218 q[ i ] = ( 1.0 - t ) * q[ i ] + t * q[ i + 1 ];
226 * ( q[ 2 ] - 2 * q[ 1 ] + q[ 0 ] );
230 else if( j ==
degree() - 1 )
233 *d1 =
degree() * ( q[ 1 ] - q[ 0 ] );
259 KoPoint* tn, KoPoint* n )
const
271 sqrt( d.x() * d.x() + d.y() * d.y() );
273 d = norm ? d * ( 1.0 / norm ) : KoPoint( 0.0, 0.0 );
293 if( !
prev() || t == 0.0 )
322 path.append( this->
clone() );
325 VSegment* copy = this->
clone();
326 path.append( copy->
splitAt( t ) );
336 while( path.current() )
343 ( poly - chord ) / poly > VGlobal::lengthTolerance )
347 path.current()->
splitAt( 0.5 ) );
351 length += 0.5 * poly + 0.5 * chord;
369 return sqrt( d * d );
382 double length = sqrt( d * d );
385 for(
unsigned short i = 1; i <
degree(); ++i )
416 double paramMid = 0.5;
419 double lengthMid =
length( paramMid );
421 while( TQABS( lengthMid - len ) / len > VGlobal::paramLengthTolerance )
423 if( lengthMid < len )
428 paramMid = 0.5 * ( param2 + param1 );
430 lengthMid =
length( paramMid );
480 KoPoint* c =
new KoPoint[
degree() + 1 ];
484 for(
unsigned short i = 1; i <=
degree(); ++i )
486 c[ i ] =
point( i - 1 ) -
p;
491 KoPoint* d =
new KoPoint[
degree() ];
495 for(
unsigned short j = 1; j <=
degree() - 1; ++j )
497 d[ j ] = 3.0 * (
point( j ) -
point( j - 1 ) );
504 for(
unsigned short j = 0; j <=
degree() - 1; ++j )
506 for(
unsigned short i = 0; i <=
degree(); ++i )
508 z[ j * (
degree() + 1 ) + i ] =
510 VGlobal::binomialCoeff(
degree(), i ) *
511 VGlobal::binomialCoeff(
degree() - i, j ) )
514 VGlobal::binomialCoeff( 2 *
degree() - 1, i + j ) );
520 double* products =
new double[
degree() * (
degree() + 1 ) ];
522 for(
unsigned short j = 0; j <=
degree() - 1; ++j )
524 for(
unsigned short i = 0; i <=
degree(); ++i )
526 products[ j * (
degree() + 1 ) + i ] =
537 VSubpath newCurve( 0L );
538 newCurve.append(
new VSegment( 2 *
degree() - 1 ) );
541 for(
unsigned short u = 0; u <= 2 *
degree() - 1; ++u )
543 newCurve.current()->
setP(
546 static_cast<double>( u ) /
static_cast<double>( 2 *
degree() - 1 ),
552 for(
unsigned short k = 0; k <= 2 *
degree() - 1; ++k )
554 unsigned short min = kMin( k,
degree() );
557 unsigned short i = kMax( 0, k - (
degree() - 1 ) );
561 unsigned short j = k - i;
564 newCurve.getLast()->
setP(
567 newCurve.getLast()->
p( k ).x(),
568 newCurve.getLast()->
p( k ).y() +
569 products[ j * (
degree() + 1 ) + i ] *
570 z[ j * (
degree() + 1 ) + i ] ) );
575 delete[]( products );
578kdDebug(38000) <<
"results" << endl;
579for(
int i = 0; i <= 2 *
degree() - 1; ++i )
581kdDebug(38000) << newCurve.getLast()->
p( i ).x() <<
" "
582<< newCurve.getLast()->
p( i ).y() << endl;
584kdDebug(38000) << endl;
587 TQValueList<double> params;
589 newCurve.getLast()->rootParams( params );
594 double distanceSquared;
595 double oldDistanceSquared;
600 distanceSquared = dist * dist;
604 for( TQValueListConstIterator<double> itr = params.begin(); itr != params.end(); ++itr )
608 oldDistanceSquared = distanceSquared;
609 distanceSquared = dist * dist;
611 if( distanceSquared < oldDistanceSquared )
617 oldDistanceSquared = distanceSquared;
618 distanceSquared = dist * dist;
620 if( distanceSquared < oldDistanceSquared )
628VSegment::rootParams( TQValueList<double>& params )
const
638 switch( controlPolygonZeros() )
651<<
knot().x() <<
" " <<
knot().y() <<
" ---> "
652<< ( chord.x() *
prev()->
knot().y() - chord.y() *
prev()->
knot().x() ) / - chord.y() << endl;
663 VSubpath path( *
this );
664 path.insert( path.current()->splitAt( 0.5 ) );
666 path.current()->rootParams( params );
667 path.next()->rootParams( params );
671VSegment::controlPolygonZeros()
const
681 int sign = VGlobal::sign(
prev()->
knot().y() );
684 for(
unsigned short i = 0; i <
degree(); ++i )
687 sign = VGlobal::sign(
point( i ).y() );
689 if( sign != oldSign )
713 next.pointTangentNormalAt( 0.0, 0L, &t2 );
717 if( t1 * t2 >= VGlobal::parallelTolerance )
732 if(
prev()->
knot().x() < rect.left() )
735 if(
prev()->
knot().x() > rect.right() )
736 rect.setRight(
prev()->
knot().x() );
738 if(
prev()->
knot().y() < rect.top() )
741 if(
prev()->
knot().y() > rect.bottom() )
742 rect.setBottom(
prev()->
knot().y() );
774 KoPoint x0 =
p(1)-
p(0);
775 KoPoint x1 =
p(2)-
p(1);
776 KoPoint x2 =
p(3)-
p(2);
779 KoPoint a = x2 - 2.0*x1 + x0;
780 KoPoint b = 2.0*x1 - 2.0*x0;
786 t[0] = - c.x() / b.x();
791 double rx = b.x()*b.x() - 4.0*a.x()*c.x();
794 t[0] = ( -b.x() + sqrt( rx ) ) / (2.0*a.x());
795 t[1] = ( -b.x() - sqrt( rx ) ) / (2.0*a.x());
801 t[2] = - c.y() / b.y();
806 double ry = b.y()*b.y() - 4.0*a.y()*c.y();
809 t[2] = ( -b.y() + sqrt( ry ) ) / (2.0*a.y());
810 t[3] = ( -b.y() - sqrt( ry ) ) / (2.0*a.y());
814 for(
int i = 0; i < 4; ++i )
816 if( t[i] >= 0.0 && t[i] <= 1.0 )
820 if(
p.x() < rect.left() )
821 rect.setLeft(
p.x() );
823 if(
p.x() > rect.right() )
824 rect.setRight(
p.x() );
826 if(
p.y() < rect.top() )
827 rect.setTop(
p.y() );
829 if(
p.y() > rect.bottom() )
830 rect.setBottom(
p.y() );
837 for(
unsigned short i = 0; i <
degree() - 1; ++i )
839 if(
point( i ).x() < rect.left() )
840 rect.setLeft(
point( i ).x() );
842 if(
point( i ).x() > rect.right() )
843 rect.setRight(
point( i ).x() );
845 if(
point( i ).y() < rect.top() )
846 rect.setTop(
point( i ).y() );
848 if(
point( i ).y() > rect.bottom() )
849 rect.setBottom(
point( i ).y() );
866 VSegment* segment =
new VSegment(
degree() );
869 segment->m_state = m_state;
886 KoPoint* q =
new KoPoint[
degree() + 1 ];
890 for(
unsigned short i = 0; i <
degree(); ++i )
892 q[ i + 1 ] =
point( i );
897 for(
unsigned short j = 1; j <=
degree(); ++j )
899 for(
unsigned short i = 0; i <=
degree() - j; ++i )
901 q[ i ] = ( 1.0 - t ) * q[ i ] + t * q[ i + 1 ];
909 for(
unsigned short i = 1; i <
degree(); ++i )
930 p.x() * a.y() + b.x() *
p.y() -
p.x() * b.y() -
931 a.x() *
p.y() + a.x() * b.y() - b.x() * a.y();
934 const KoPoint ab = b - a;
935 const double norm = sqrt( ab * ab );
938 if( norm < VGlobal::verySmallNumber )
941 (
p.x() - a.x() ) * (
p.x() - a.x() ) +
942 (
p.y() - a.y() ) * (
p.y() - a.y() ) );
945 return TQABS( det ) / norm;
955 const KoPoint delta_a = a1 - a0;
956 const double det_a = a1.x() * a0.y() - a1.y() * a0.x();
958 const double r_b0 = delta_a.y() * b0.x() - delta_a.x() * b0.y() + det_a;
959 const double r_b1 = delta_a.y() * b1.x() - delta_a.x() * b1.y() + det_a;
961 if( r_b0 != 0.0 && r_b1 != 0.0 && r_b0 * r_b1 > 0.0 )
964 const KoPoint delta_b = b1 - b0;
966 const double det_b = b1.x() * b0.y() - b1.y() * b0.x();
968 const double r_a0 = delta_b.y() * a0.x() - delta_b.x() * a0.y() + det_b;
969 const double r_a1 = delta_b.y() * a1.x() - delta_b.x() * a1.y() + det_b;
971 if( r_a0 != 0.0 && r_a1 != 0.0 && r_a0 * r_a1 > 0.0 )
998 for(
unsigned short i = 0; i <
degree(); ++i )
1000 if(
point( 0 ).isNear(
p, isNearRange ) )
1017 VSegment* segment =
new VSegment(
degree() );
1019 segment->m_state = m_state;
1023 for(
unsigned short i = 0; i <
degree() - 1; ++i )
1039 VSegment* segment = m_prev;
1041 while( segment && segment->
state() == deleted )
1043 segment = segment->m_prev;
1052 VSegment* segment = m_next;
1054 while( segment && segment->
state() == deleted )
1056 segment = segment->m_next;
1064VSegment::load(
const TQDomElement& element )
1066 if( element.tagName() ==
"CURVE" )
1073 element.attribute(
"x1" ).toDouble(),
1074 element.attribute(
"y1" ).toDouble() ) );
1079 element.attribute(
"x2" ).toDouble(),
1080 element.attribute(
"y2" ).toDouble() ) );
1084 element.attribute(
"x3" ).toDouble(),
1085 element.attribute(
"y3" ).toDouble() ) );
1087 else if( element.tagName() ==
"LINE" )
1093 element.attribute(
"x" ).toDouble(),
1094 element.attribute(
"y" ).toDouble() ) );
1096 else if( element.tagName() ==
"MOVE" )
1102 element.attribute(
"x" ).toDouble(),
1103 element.attribute(
"y" ).toDouble() ) );
1110 return new VSegment( *
this );
A class representing lines and beziers.
bool pointIsSelected(int i) const
Returns true if the point with index 0 <= i < degree() is selected.
double length(double t=1.0) const
Calculates the arclength from p0 to the point parametrized by 0 <= t <= 1.
static bool linesIntersect(const KoPoint &a0, const KoPoint &a1, const KoPoint &b0, const KoPoint &b1)
Calculates whether lines A0A1 and B0B1 intersect.
double lengthParam(double len) const
Calculates the parameter of a point located at arclength len.
VSegment * next() const
Returns a pointer to the next not deleted segment, if stored in a VSubpath.
bool isFlat(double flatness=VGlobal::flatnessTolerance) const
Returns true if the segment is flat.
void pointTangentNormalAt(double t, KoPoint *p=0L, KoPoint *tn=0L, KoPoint *n=0L) const
Calculates the point, the tangent vector and the normal vector for 0 <= t <= 1.
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.
KoPoint tangentAt(double t) const
Calculates the normalized tangent vector (length=1) at the point parameterized by 0 <= t <= 1.
void setKnot(const KoPoint &p)
Sets the knot.
bool isSmooth(const VSegment &next) const
Calculates wether the tangent at the knot is exactly parallel to the tangent at p0 of the next segmen...
void setPoint(int i, const KoPoint &p)
Sets the segment's point with index 0 <= i < degree() to "p".
void pointDerivativesAt(double t, KoPoint *p=0L, KoPoint *d1=0L, KoPoint *d2=0L) const
Calculates the point and the derivatives of first and second order for 0 <= t <= 1.
static double height(const KoPoint &a, const KoPoint &p, const KoPoint &b)
Calculates height of point p above line AB.
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 * splitAt(double t)
Splits the segment at parameter 0 <= t <= 1.
double polyLength() const
Calculates the length of the control polygon.
void selectPoint(int i, bool select=true)
Selects the point with index 0 <= i < degree().
VSegment * prev() const
Returns a pointer to the previous not deleted segment, if stored in a VSubpath.
KoPoint pointAt(double t) const
Calculates the point on this segment at parameter 0 <= t <= 1.
double nearestPointParam(const KoPoint &p) const
Calculates the parameter of the nearest point on this segment to the point p.
double chordLength() const
Calculates the chord length (the distance from the previous knot to the current knot).
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().
uint nodeNear(const KoPoint &p, double isNearRange=VGlobal::isNearRange) const
Returns index of the node at point p.
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.