Warning, file /office/calligra/libs/flake/KoPathSegment.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2008-2009 Jan Hambrecht <jaham@gmx.net>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "KoPathSegment.h"
0021 #include "KoPathPoint.h"
0022 #include <FlakeDebug.h>
0023 #include <QPainterPath>
0024 #include <QTransform>
0025 #include <math.h>
0026 
0027 /// Maximal recursion depth for finding root params
0028 const int MaxRecursionDepth = 64;
0029 /// Flatness tolerance for finding root params
0030 const qreal FlatnessTolerance = ldexp(1.0,-MaxRecursionDepth-1);
0031 
0032 class BezierSegment
0033 {
0034 public:
0035     BezierSegment(int degree = 0, QPointF *p = 0)
0036     {
0037         if (degree) {
0038             for (int i = 0; i <= degree; ++i)
0039                 points.append(p[i]);
0040         }
0041     }
0042 
0043     void setDegree(int degree)
0044     {
0045         points.clear();
0046         if (degree) {
0047             points.reserve(degree+1);
0048             for (int i = 0; i <= degree; ++i)
0049                 points.append(QPointF());
0050         }
0051     }
0052 
0053     int degree() const
0054     {
0055         return points.count() - 1;
0056     }
0057 
0058     QPointF point(int index) const
0059     {
0060         if (static_cast<int>(index) > degree())
0061             return QPointF();
0062 
0063         return points[index];
0064     }
0065 
0066     void setPoint(int index, const QPointF &p)
0067     {
0068         if (static_cast<int>(index) > degree())
0069             return;
0070 
0071         points[index] = p;
0072     }
0073 
0074     QPointF evaluate(qreal t, BezierSegment *left, BezierSegment *right) const
0075     {
0076         int deg = degree();
0077         if (! deg)
0078             return QPointF();
0079 
0080         QVector<QVector<QPointF> > Vtemp(deg + 1);
0081         for (int i = 0; i <= deg; ++i)
0082             Vtemp[i].resize(deg + 1);
0083 
0084         /* Copy control points  */
0085         for (int j = 0; j <= deg; j++) {
0086             Vtemp[0][j] = points[j];
0087         }
0088 
0089         /* Triangle computation */
0090         for (int i = 1; i <= deg; i++) {
0091             for (int j =0 ; j <= deg - i; j++) {
0092                 Vtemp[i][j].rx() = (1.0 - t) * Vtemp[i-1][j].x() + t * Vtemp[i-1][j+1].x();
0093                 Vtemp[i][j].ry() = (1.0 - t) * Vtemp[i-1][j].y() + t * Vtemp[i-1][j+1].y();
0094             }
0095         }
0096 
0097         if (left) {
0098             left->setDegree(deg);
0099             for (int j = 0; j <= deg; j++) {
0100                 left->setPoint(j, Vtemp[j][0]);
0101             }
0102         }
0103         if (right) {
0104             right->setDegree(deg);
0105             for (int j = 0; j <= deg; j++) {
0106                 right->setPoint(j, Vtemp[deg-j][j]);
0107             }
0108         }
0109 
0110         return (Vtemp[deg][0]);
0111     }
0112 
0113     QList<qreal> roots(int depth = 0) const
0114     {
0115         QList<qreal> rootParams;
0116 
0117         if (! degree())
0118             return rootParams;
0119 
0120         // Calculate how often the control polygon crosses the x-axis
0121         // This is the upper limit for the number of roots.
0122         int xAxisCrossings = controlPolygonZeros(points);
0123 
0124         if (! xAxisCrossings) {
0125             // No solutions.
0126             return rootParams;
0127         }
0128         else if (xAxisCrossings == 1) {
0129             // Exactly one solution.
0130 
0131             // Stop recursion when the tree is deep enough
0132             if (depth >= MaxRecursionDepth) {
0133                 // if deep enough, return 1 solution at midpoint
0134                 rootParams.append((points.first().x() + points.last().x()) / 2.0);
0135                 return rootParams;
0136             }
0137             else if (isFlat(FlatnessTolerance)) {
0138                 // Calculate intersection of chord with x-axis.
0139                 QPointF chord = points.last() - points.first();
0140                 QPointF segStart = points.first();
0141                 rootParams.append((chord.x() * segStart.y() - chord.y() * segStart.x()) / - chord.y());
0142                 return rootParams;
0143             }
0144         }
0145 
0146         // Many solutions. Do recursive midpoint subdivision.
0147         BezierSegment left, right;
0148         evaluate(0.5, &left, &right);
0149         rootParams += left.roots(depth+1);
0150         rootParams += right.roots(depth+1);
0151 
0152         return rootParams;
0153     }
0154 
0155     static uint controlPolygonZeros(const QVector<QPointF> &controlPoints)
0156     {
0157         int controlPointCount = controlPoints.count();
0158         if (controlPointCount < 2)
0159             return 0;
0160 
0161         int signChanges = 0;
0162 
0163         int currSign = controlPoints[0].y() < 0.0 ? -1 : 1;
0164         int oldSign;
0165 
0166         for (short i = 1; i < controlPointCount; ++i) {
0167             oldSign = currSign;
0168             currSign = controlPoints[i].y() < 0.0 ? -1 : 1;
0169 
0170             if (currSign != oldSign) {
0171                 ++signChanges;
0172             }
0173         }
0174 
0175 
0176         return signChanges;
0177     }
0178 
0179     int isFlat (qreal tolerance) const
0180     {
0181         int deg = degree();
0182 
0183         // Find the  perpendicular distance from each interior control point to
0184         // the line connecting points[0] and points[degree]
0185         qreal *distance = new qreal[deg + 1];
0186 
0187         // Derive the implicit equation for line connecting first and last control points
0188         qreal a = points[0].y() - points[deg].y();
0189         qreal b = points[deg].x() - points[0].x();
0190         qreal c = points[0].x() * points[deg].y() - points[deg].x() * points[0].y();
0191 
0192         qreal abSquared = (a * a) + (b * b);
0193 
0194         for (int i = 1; i < deg; i++) {
0195             // Compute distance from each of the points to that line
0196             distance[i] = a * points[i].x() + b * points[i].y() + c;
0197             if (distance[i] > 0.0) {
0198                 distance[i] = (distance[i] * distance[i]) / abSquared;
0199             }
0200             if (distance[i] < 0.0) {
0201                 distance[i] = -((distance[i] * distance[i]) / abSquared);
0202             }
0203         }
0204 
0205 
0206         // Find the largest distance
0207         qreal max_distance_above = 0.0;
0208         qreal max_distance_below = 0.0;
0209         for (int i = 1; i < deg; i++) {
0210             if (distance[i] < 0.0) {
0211                 max_distance_below = qMin(max_distance_below, distance[i]);
0212             }
0213             if (distance[i] > 0.0) {
0214                 max_distance_above = qMax(max_distance_above, distance[i]);
0215             }
0216         }
0217         delete [] distance;
0218 
0219         // Implicit equation for zero line
0220         qreal a1 = 0.0;
0221         qreal b1 = 1.0;
0222         qreal c1 = 0.0;
0223 
0224         // Implicit equation for "above" line
0225         qreal a2 = a;
0226         qreal b2 = b;
0227         qreal c2 = c + max_distance_above;
0228 
0229         qreal det = a1 * b2 - a2 * b1;
0230         qreal dInv = 1.0/det;
0231 
0232         qreal intercept_1 = (b1 * c2 - b2 * c1) * dInv;
0233 
0234         // Implicit equation for "below" line
0235         a2 = a;
0236         b2 = b;
0237         c2 = c + max_distance_below;
0238 
0239         det = a1 * b2 - a2 * b1;
0240         dInv = 1.0/det;
0241 
0242         qreal intercept_2 = (b1 * c2 - b2 * c1) * dInv;
0243 
0244         // Compute intercepts of bounding box
0245         qreal left_intercept = qMin(intercept_1, intercept_2);
0246         qreal right_intercept = qMax(intercept_1, intercept_2);
0247 
0248         qreal error = 0.5 * (right_intercept-left_intercept);
0249 
0250         return (error < tolerance);
0251     }
0252 
0253 #ifndef NDEBUG
0254     void printDebug() const
0255     {
0256         int index = 0;
0257         // There exists a problem on msvc with for(each) and QVector<QPointF>
0258         for (int i = 0; i < points.count(); ++i) {
0259             const QPointF p(points[i]);
0260             debugFlake << QString("P%1 ").arg(index++) << p;
0261         }
0262     }
0263 #endif
0264 
0265 private:
0266     QVector<QPointF> points;
0267 };
0268 
0269 class Q_DECL_HIDDEN KoPathSegment::Private
0270 {
0271 public:
0272     Private(KoPathSegment *qq, KoPathPoint *p1, KoPathPoint *p2)
0273         : first(p1),
0274         second(p2),
0275         q(qq)
0276     {
0277     }
0278 
0279     /// calculates signed distance of given point from segment chord
0280     qreal distanceFromChord(const QPointF &point) const;
0281 
0282     /// Returns the chord length, i.e. the distance between first and last control point
0283     qreal chordLength() const;
0284 
0285     /// Returns intersection of lines if one exists
0286     QVector<QPointF> linesIntersection(const KoPathSegment &segment) const;
0287 
0288     /// Returns parameters for curve extrema
0289     QList<qreal> extrema() const;
0290 
0291     /// Returns parameters for curve roots
0292     QList<qreal> roots() const;
0293 
0294     /**
0295      * The DeCasteljau algorithm for parameter t.
0296      * @param t the parameter to evaluate at
0297      * @param p1 the new control point of the segment start (for cubic curves only)
0298      * @param p2 the first control point at t
0299      * @param p3 the new point at t
0300      * @param p4 the second control point at t
0301      * @param p3 the new control point of the segment end (for cubic curves only)
0302      */
0303     void deCasteljau(qreal t, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4, QPointF *p5) const;
0304 
0305     KoPathPoint *first;
0306     KoPathPoint *second;
0307     KoPathSegment *q;
0308 };
0309 
0310 void KoPathSegment::Private::deCasteljau(qreal t, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4, QPointF *p5) const
0311 {
0312     if (!q->isValid())
0313       return;
0314 
0315     int deg = q->degree();
0316     QPointF q[4];
0317 
0318     q[0] = first->point();
0319     if (deg == 2) {
0320         q[1] = first->activeControlPoint2() ? first->controlPoint2() : second->controlPoint1();
0321     } else if (deg == 3) {
0322         q[1] = first->controlPoint2();
0323         q[2] = second->controlPoint1();
0324     }
0325     q[deg] = second->point();
0326 
0327     // points of the new segment after the split point
0328     QPointF p[3];
0329 
0330     // the De Casteljau algorithm
0331     for (unsigned short j = 1; j <= deg; ++j) {
0332         for (unsigned short i = 0; i <= deg - j; ++i) {
0333             q[i] = (1.0 - t) * q[i] + t * q[i + 1];
0334         }
0335         p[j - 1] = q[0];
0336     }
0337 
0338     if (deg == 2) {
0339         if (p2)
0340             *p2 = p[0];
0341         if (p3)
0342             *p3 = p[1];
0343         if (p4)
0344             *p4 = q[1];
0345     } else if (deg == 3) {
0346         if (p1)
0347             *p1 = p[0];
0348         if (p2)
0349             *p2 = p[1];
0350         if (p3)
0351             *p3 = p[2];
0352         if (p4)
0353             *p4 = q[1];
0354         if (p5)
0355             *p5 = q[2];
0356     }
0357 }
0358 
0359 QList<qreal> KoPathSegment::Private::roots() const
0360 {
0361     QList<qreal> rootParams;
0362 
0363     if (!q->isValid())
0364         return rootParams;
0365 
0366     // Calculate how often the control polygon crosses the x-axis
0367     // This is the upper limit for the number of roots.
0368     int xAxisCrossings = BezierSegment::controlPolygonZeros(q->controlPoints());
0369 
0370     if (!xAxisCrossings) {
0371         // No solutions.
0372     }
0373     else if (xAxisCrossings == 1 && q->isFlat(0.01 / chordLength())) {
0374         // Exactly one solution.
0375         // Calculate intersection of chord with x-axis.
0376         QPointF chord = second->point() - first->point();
0377         QPointF segStart = first->point();
0378         rootParams.append((chord.x() * segStart.y() - chord.y() * segStart.x()) / - chord.y());
0379     }
0380     else {
0381         // Many solutions. Do recursive midpoint subdivision.
0382         QPair<KoPathSegment, KoPathSegment> splitSegments = q->splitAt(0.5);
0383         rootParams += splitSegments.first.d->roots();
0384         rootParams += splitSegments.second.d->roots();
0385     }
0386 
0387     return rootParams;
0388 }
0389 
0390 QList<qreal> KoPathSegment::Private::extrema() const
0391 {
0392     int deg = q->degree();
0393     if (deg <= 1)
0394         return QList<qreal>();
0395 
0396     QList<qreal> params;
0397 
0398     /*
0399      * The basic idea for calculating the extrema for bezier segments
0400      * was found in comp.graphics.algorithms:
0401      *
0402      * Both the x coordinate and the y coordinate are polynomial. Newton told
0403      * us that at a maximum or minimum the derivative will be zero.
0404      *
0405      * We have a helpful trick for the derivatives: use the curve r(t) defined by
0406      * differences of successive control points.
0407      * Setting r(t) to zero and using the x and y coordinates of differences of
0408      * successive control points lets us find the parameters t, where the original
0409      * bezier curve has a minimum or a maximum.
0410      */
0411     if (deg == 2) {
0412         /*
0413          * For quadratic bezier curves r(t) is a linear Bezier curve:
0414          *
0415          *  1
0416          * r(t) = Sum Bi,1(t) *Pi = B0,1(t) * P0 + B1,1(t) * P1
0417          * i=0
0418          *
0419          * r(t) = (1-t) * P0 + t * P1
0420          *
0421          * r(t) = (P1 - P0) * t + P0
0422          */
0423 
0424         // calculating the differences between successive control points
0425         QPointF cp = first->activeControlPoint2() ?
0426                      first->controlPoint2() : second->controlPoint1();
0427         QPointF x0 = cp - first->point();
0428         QPointF x1 = second->point() - cp;
0429 
0430         // calculating the coefficients
0431         QPointF a = x1 - x0;
0432         QPointF c = x0;
0433 
0434         if (a.x() != 0.0)
0435             params.append(-c.x() / a.x());
0436         if (a.y() != 0.0)
0437             params.append(-c.y() / a.y());
0438     } else if (deg == 3) {
0439         /*
0440          * For cubic bezier curves r(t) is a quadratic Bezier curve:
0441          *
0442          *  2
0443          * r(t) = Sum Bi,2(t) *Pi = B0,2(t) * P0 + B1,2(t) * P1 + B2,2(t) * P2
0444          * i=0
0445          *
0446          * r(t) = (1-t)^2 * P0 + 2t(1-t) * P1 + t^2 * P2
0447          *
0448          * r(t) = (P2 - 2*P1 + P0) * t^2 + (2*P1 - 2*P0) * t + P0
0449          *
0450          */
0451         // calcualting the differences between successive control points
0452         QPointF x0 = first->controlPoint2() - first->point();
0453         QPointF x1 = second->controlPoint1() - first->controlPoint2();
0454         QPointF x2 = second->point() - second->controlPoint1();
0455 
0456         // calculating the coefficents
0457         QPointF a = x2 - 2.0 * x1 + x0;
0458         QPointF b = 2.0 * x1 - 2.0 * x0;
0459         QPointF c = x0;
0460 
0461         // calculating parameter t at minimum/maximum in x-direction
0462         if (a.x() == 0.0) {
0463             params.append(- c.x() / b.x());
0464         } else {
0465             qreal rx = b.x() * b.x() - 4.0 * a.x() * c.x();
0466             if (rx < 0.0)
0467                 rx = 0.0;
0468             params.append((-b.x() + sqrt(rx)) / (2.0*a.x()));
0469             params.append((-b.x() - sqrt(rx)) / (2.0*a.x()));
0470         }
0471 
0472         // calculating parameter t at minimum/maximum in y-direction
0473         if (a.y() == 0.0) {
0474             params.append(- c.y() / b.y());
0475         } else {
0476             qreal ry = b.y() * b.y() - 4.0 * a.y() * c.y();
0477             if (ry < 0.0)
0478                 ry = 0.0;
0479             params.append((-b.y() + sqrt(ry)) / (2.0*a.y()));
0480             params.append((-b.y() - sqrt(ry)) / (2.0*a.y()));
0481         }
0482     }
0483 
0484     return params;
0485 }
0486 
0487 qreal KoPathSegment::Private::distanceFromChord(const QPointF &point) const
0488 {
0489     // the segments chord
0490     QPointF chord = second->point() - first->point();
0491     // the point relative to the segment
0492     QPointF relPoint = point - first->point();
0493     // project point to chord
0494     qreal scale = chord.x() * relPoint.x() + chord.y() * relPoint.y();
0495     scale /= chord.x() * chord.x() + chord.y() * chord.y();
0496 
0497     // the vector form the point to the projected point on the chord
0498     QPointF diffVec = scale * chord - relPoint;
0499 
0500     // the unsigned distance of the point to the chord
0501     qreal distance = sqrt(diffVec.x() * diffVec.x() + diffVec.y() * diffVec.y());
0502 
0503     // determine sign of the distance using the cross product
0504     if (chord.x()*relPoint.y() - chord.y()*relPoint.x() > 0) {
0505         return distance;
0506     } else {
0507         return -distance;
0508     }
0509 }
0510 
0511 qreal KoPathSegment::Private::chordLength() const
0512 {
0513     QPointF chord = second->point() - first->point();
0514     return sqrt(chord.x() * chord.x() + chord.y() * chord.y());
0515 }
0516 
0517 QVector<QPointF> KoPathSegment::Private::linesIntersection(const KoPathSegment &segment) const
0518 {
0519     //debugFlake << "intersecting two lines";
0520     /*
0521     we have to line segments:
0522 
0523     s1 = A + r * (B-A), s2 = C + s * (D-C) for r,s in [0,1]
0524 
0525         if s1 and s2 intersect we set s1 = s2 so we get these two equations:
0526 
0527     Ax + r * (Bx-Ax) = Cx + s * (Dx-Cx)
0528     Ay + r * (By-Ay) = Cy + s * (Dy-Cy)
0529 
0530     which we can solve to get r and s
0531     */
0532     QVector<QPointF> isects;
0533     QPointF A = first->point();
0534     QPointF B = second->point();
0535     QPointF C = segment.first()->point();
0536     QPointF D = segment.second()->point();
0537 
0538     qreal denom = (B.x() - A.x()) * (D.y() - C.y()) - (B.y() - A.y()) * (D.x() - C.x());
0539     qreal num_r = (A.y() - C.y()) * (D.x() - C.x()) - (A.x() - C.x()) * (D.y() - C.y());
0540     // check if lines are collinear
0541     if (denom == 0.0 && num_r == 0.0)
0542         return isects;
0543 
0544     qreal num_s = (A.y() - C.y()) * (B.x() - A.x()) - (A.x() - C.x()) * (B.y() - A.y());
0545     qreal r = num_r / denom;
0546     qreal s = num_s / denom;
0547 
0548     // check if intersection is inside our line segments
0549     if (r < 0.0 || r > 1.0)
0550         return isects;
0551     if (s < 0.0 || s > 1.0)
0552         return isects;
0553 
0554     // calculate the actual intersection point
0555     isects.append(A + r * (B - A));
0556 
0557     return isects;
0558 }
0559 
0560 
0561 ///////////////////
0562 KoPathSegment::KoPathSegment(KoPathPoint * first, KoPathPoint * second)
0563     : d(new Private(this, first, second))
0564 {
0565 }
0566 
0567 KoPathSegment::KoPathSegment(const KoPathSegment & segment)
0568     : d(new Private(this, 0, 0))
0569 {
0570     if (! segment.first() || segment.first()->parent())
0571         setFirst(segment.first());
0572     else
0573         setFirst(new KoPathPoint(*segment.first()));
0574 
0575     if (! segment.second() || segment.second()->parent())
0576         setSecond(segment.second());
0577     else
0578         setSecond(new KoPathPoint(*segment.second()));
0579 }
0580 
0581 KoPathSegment::KoPathSegment(const QPointF &p0, const QPointF &p1)
0582     : d(new Private(this, new KoPathPoint(), new KoPathPoint()))
0583 {
0584     d->first->setPoint(p0);
0585     d->second->setPoint(p1);
0586 }
0587 
0588 KoPathSegment::KoPathSegment(const QPointF &p0, const QPointF &p1, const QPointF &p2)
0589     : d(new Private(this, new KoPathPoint(), new KoPathPoint()))
0590 {
0591     d->first->setPoint(p0);
0592     d->first->setControlPoint2(p1);
0593     d->second->setPoint(p2);
0594 }
0595 
0596 KoPathSegment::KoPathSegment(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3)
0597     : d(new Private(this, new KoPathPoint(), new KoPathPoint()))
0598 {
0599     d->first->setPoint(p0);
0600     d->first->setControlPoint2(p1);
0601     d->second->setControlPoint1(p2);
0602     d->second->setPoint(p3);
0603 }
0604 
0605 KoPathSegment &KoPathSegment::operator=(const KoPathSegment &rhs)
0606 {
0607     if (this == &rhs)
0608         return (*this);
0609 
0610     if (! rhs.first() || rhs.first()->parent())
0611         setFirst(rhs.first());
0612     else
0613         setFirst(new KoPathPoint(*rhs.first()));
0614 
0615     if (! rhs.second() || rhs.second()->parent())
0616         setSecond(rhs.second());
0617     else
0618         setSecond(new KoPathPoint(*rhs.second()));
0619 
0620     return (*this);
0621 }
0622 
0623 KoPathSegment::~KoPathSegment()
0624 {
0625     if (d->first && ! d->first->parent())
0626         delete d->first;
0627     if (d->second && ! d->second->parent())
0628         delete d->second;
0629     delete d;
0630 }
0631 
0632 KoPathPoint *KoPathSegment::first() const
0633 {
0634     return d->first;
0635 }
0636 
0637 void KoPathSegment::setFirst(KoPathPoint *first)
0638 {
0639     if (d->first && !d->first->parent())
0640         delete d->first;
0641     d->first = first;
0642 }
0643 
0644 KoPathPoint *KoPathSegment::second() const
0645 {
0646     return d->second;
0647 }
0648 
0649 void KoPathSegment::setSecond(KoPathPoint *second)
0650 {
0651     if (d->second && !d->second->parent())
0652         delete d->second;
0653     d->second = second;
0654 }
0655 
0656 bool KoPathSegment::isValid() const
0657 {
0658     return (d->first && d->second);
0659 }
0660 
0661 bool KoPathSegment::operator==(const KoPathSegment &rhs) const
0662 {
0663     if (!isValid() && !rhs.isValid())
0664         return true;
0665     if (isValid() && !rhs.isValid())
0666         return false;
0667     if (!isValid() && rhs.isValid())
0668         return false;
0669 
0670     return (*first() == *rhs.first() && *second() == *rhs.second());
0671 }
0672 
0673 int KoPathSegment::degree() const
0674 {
0675     if (!d->first || !d->second)
0676         return -1;
0677 
0678     bool c1 = d->first->activeControlPoint2();
0679     bool c2 = d->second->activeControlPoint1();
0680     if (!c1 && !c2)
0681         return 1;
0682     if (c1 && c2)
0683         return 3;
0684     return 2;
0685 }
0686 
0687 QPointF KoPathSegment::pointAt(qreal t) const
0688 {
0689     if (!isValid())
0690         return QPointF();
0691 
0692     if (degree() == 1) {
0693         return d->first->point() + t * (d->second->point() - d->first->point());
0694     } else {
0695         QPointF splitP;
0696 
0697         d->deCasteljau(t, 0, 0, &splitP, 0, 0);
0698 
0699         return splitP;
0700     }
0701 }
0702 
0703 QRectF KoPathSegment::controlPointRect() const
0704 {
0705     if (!isValid())
0706         return QRectF();
0707 
0708     const QVector<QPointF> points = controlPoints();
0709     QRectF bbox(points.first(), points.first());
0710     // There exists a problem on msvc with for(each) and QVector<QPointF>
0711     for (int i = 0; i < points.count(); ++i) {
0712         const QPointF p(points[i]);
0713         bbox.setLeft(qMin(bbox.left(), p.x()));
0714         bbox.setRight(qMax(bbox.right(), p.x()));
0715         bbox.setTop(qMin(bbox.top(), p.y()));
0716         bbox.setBottom(qMax(bbox.bottom(), p.y()));
0717     }
0718 
0719     if (degree() == 1) {
0720         // adjust bounding rect of horizontal and vertical lines
0721         if (bbox.height() == 0.0)
0722             bbox.setHeight(0.1);
0723         if (bbox.width() == 0.0)
0724             bbox.setWidth(0.1);
0725     }
0726 
0727     return bbox;
0728 }
0729 
0730 QRectF KoPathSegment::boundingRect() const
0731 {
0732     if (!isValid())
0733         return QRectF();
0734 
0735     QRectF rect = QRectF(d->first->point(), d->second->point()).normalized();
0736 
0737     if (degree() == 1) {
0738         // adjust bounding rect of horizontal and vertical lines
0739         if (rect.height() == 0.0)
0740             rect.setHeight(0.1);
0741         if (rect.width() == 0.0)
0742             rect.setWidth(0.1);
0743     } else {
0744         /*
0745          * The basic idea for calculating the axis aligned bounding box (AABB) for bezier segments
0746          * was found in comp.graphics.algorithms:
0747          * Use the points at the extrema of the curve to calculate the AABB.
0748          */
0749         for (qreal t : d->extrema()) {
0750             if (t >= 0.0 && t <= 1.0) {
0751                 QPointF p = pointAt(t);
0752                 rect.setLeft(qMin(rect.left(), p.x()));
0753                 rect.setRight(qMax(rect.right(), p.x()));
0754                 rect.setTop(qMin(rect.top(), p.y()));
0755                 rect.setBottom(qMax(rect.bottom(), p.y()));
0756             }
0757         }
0758     }
0759 
0760     return rect;
0761 }
0762 
0763 QVector<QPointF> KoPathSegment::intersections(const KoPathSegment &segment) const
0764 {
0765     // this function uses a technique known as bezier clipping to find the
0766     // intersections of the two bezier curves
0767 
0768     QVector<QPointF> isects;
0769 
0770     if (!isValid() || !segment.isValid())
0771         return isects;
0772 
0773     int degree1 = degree();
0774     int degree2 = segment.degree();
0775 
0776     QRectF myBound = boundingRect();
0777     QRectF otherBound = segment.boundingRect();
0778     //debugFlake << "my boundingRect =" << myBound;
0779     //debugFlake << "other boundingRect =" << otherBound;
0780     if (!myBound.intersects(otherBound)) {
0781         //debugFlake << "segments do not intersect";
0782         return isects;
0783     }
0784 
0785     // short circuit lines intersection
0786     if (degree1 == 1 && degree2 == 1) {
0787         //debugFlake << "intersecting two lines";
0788         isects += d->linesIntersection(segment);
0789         return isects;
0790     }
0791 
0792     // first calculate the fat line L by using the signed distances
0793     // of the control points from the chord
0794     qreal dmin, dmax;
0795     if (degree1 == 1) {
0796         dmin = 0.0;
0797         dmax = 0.0;
0798     } else if (degree1 == 2) {
0799         qreal d1;
0800         if (d->first->activeControlPoint2())
0801             d1 = d->distanceFromChord(d->first->controlPoint2());
0802         else
0803             d1 = d->distanceFromChord(d->second->controlPoint1());
0804         dmin = qMin(qreal(0.0), qreal(0.5 * d1));
0805         dmax = qMax(qreal(0.0), qreal(0.5 * d1));
0806     } else {
0807         qreal d1 = d->distanceFromChord(d->first->controlPoint2());
0808         qreal d2 = d->distanceFromChord(d->second->controlPoint1());
0809         if (d1*d2 > 0.0) {
0810             dmin = 0.75 * qMin(qreal(0.0), qMin(d1, d2));
0811             dmax = 0.75 * qMax(qreal(0.0), qMax(d1, d2));
0812         } else {
0813             dmin = 4.0 / 9.0 * qMin(qreal(0.0), qMin(d1, d2));
0814             dmax = 4.0 / 9.0 * qMax(qreal(0.0), qMax(d1, d2));
0815         }
0816     }
0817 
0818     //debugFlake << "using fat line: dmax =" << dmax << " dmin =" << dmin;
0819 
0820     /*
0821       the other segment is given as a bezier curve of the form:
0822      (1) P(t) = sum_i P_i * B_{n,i}(t)
0823      our chord line is of the form:
0824      (2) ax + by + c = 0
0825      we can determine the distance d(t) from any point P(t) to our chord
0826      by substituting formula (1) into formula (2):
0827      d(t) = sum_i d_i B_{n,i}(t), where d_i = a*x_i + b*y_i + c
0828      which forms another explicit bezier curve
0829      D(t) = (t,d(t)) = sum_i D_i B_{n,i}(t)
0830      now values of t for which P(t) lies outside of our fat line L
0831      corresponds to values of t for which D(t) lies above d = dmax or
0832      below d = dmin
0833      we can determine parameter ranges of t for which P(t) is guaranteed
0834      to lie outside of L by identifying ranges of t which the convex hull
0835      of D(t) lies above dmax or below dmin
0836     */
0837     // now calculate the control points of D(t) by using the signed
0838     // distances of P_i to our chord
0839     KoPathSegment dt;
0840     if (degree2 == 1) {
0841         QPointF p0(0.0, d->distanceFromChord(segment.first()->point()));
0842         QPointF p1(1.0, d->distanceFromChord(segment.second()->point()));
0843         dt = KoPathSegment(p0, p1);
0844     } else if (degree2 == 2) {
0845         QPointF p0(0.0, d->distanceFromChord(segment.first()->point()));
0846         QPointF p1 = segment.first()->activeControlPoint2()
0847                      ? QPointF(0.5, d->distanceFromChord(segment.first()->controlPoint2()))
0848                      : QPointF(0.5, d->distanceFromChord(segment.second()->controlPoint1()));
0849         QPointF p2(1.0, d->distanceFromChord(segment.second()->point()));
0850         dt = KoPathSegment(p0, p1, p2);
0851     } else if (degree2 == 3) {
0852         QPointF p0(0.0, d->distanceFromChord(segment.first()->point()));
0853         QPointF p1(1. / 3., d->distanceFromChord(segment.first()->controlPoint2()));
0854         QPointF p2(2. / 3., d->distanceFromChord(segment.second()->controlPoint1()));
0855         QPointF p3(1.0, d->distanceFromChord(segment.second()->point()));
0856         dt = KoPathSegment(p0, p1, p2, p3);
0857     } else {
0858         //debugFlake << "invalid degree of segment -> exiting";
0859         return isects;
0860     }
0861 
0862     // get convex hull of the segment D(t)
0863     const QVector<QPointF> hull = dt.convexHull();
0864 
0865     // now calculate intersections with the line y1 = dmin, y2 = dmax
0866     // with the convex hull edges
0867     int hullCount = hull.count();
0868     qreal tmin = 1.0, tmax = 0.0;
0869     bool intersectionsFoundMax = false;
0870     bool intersectionsFoundMin = false;
0871 
0872     for (int i = 0; i < hullCount; ++i) {
0873         QPointF p1 = hull[i];
0874         QPointF p2 = hull[(i+1) % hullCount];
0875         //debugFlake << "intersecting hull edge (" << p1 << p2 << ")";
0876         // hull edge is completely above dmax
0877         if (p1.y() > dmax && p2.y() > dmax)
0878             continue;
0879         // hull egde is completely below dmin
0880         if (p1.y() < dmin && p2.y() < dmin)
0881             continue;
0882         if (p1.x() == p2.x()) {
0883             // vertical edge
0884             bool dmaxIntersection = (dmax < qMax(p1.y(), p2.y()) && dmax > qMin(p1.y(), p2.y()));
0885             bool dminIntersection = (dmin < qMax(p1.y(), p2.y()) && dmin > qMin(p1.y(), p2.y()));
0886             if (dmaxIntersection || dminIntersection) {
0887                 tmin = qMin(tmin, p1.x());
0888                 tmax = qMax(tmax, p1.x());
0889                 if (dmaxIntersection) {
0890                     intersectionsFoundMax = true;
0891                     //debugFlake << "found intersection with dmax at " << p1.x() << "," << dmax;
0892                 } else {
0893                     intersectionsFoundMin = true;
0894                     //debugFlake << "found intersection with dmin at " << p1.x() << "," << dmin;
0895                 }
0896             }
0897         } else if (p1.y() == p2.y()) {
0898             // horizontal line
0899             if (p1.y() == dmin || p1.y() == dmax) {
0900                 if (p1.y() == dmin) {
0901                     intersectionsFoundMin = true;
0902                     //debugFlake << "found intersection with dmin at " << p1.x() << "," << dmin;
0903                     //debugFlake << "found intersection with dmin at " << p2.x() << "," << dmin;
0904                 } else {
0905                     intersectionsFoundMax = true;
0906                     //debugFlake << "found intersection with dmax at " << p1.x() << "," << dmax;
0907                     //debugFlake << "found intersection with dmax at " << p2.x() << "," << dmax;
0908                 }
0909                 tmin = qMin(tmin, p1.x());
0910                 tmin = qMin(tmin, p2.x());
0911                 tmax = qMax(tmax, p1.x());
0912                 tmax = qMax(tmax, p2.x());
0913             }
0914         } else {
0915             qreal dx = p2.x() - p1.x();
0916             qreal dy = p2.y() - p1.y();
0917             qreal m = dy / dx;
0918             qreal n = p1.y() - m * p1.x();
0919             qreal t1 = (dmax - n) / m;
0920             if (t1 >= 0.0 && t1 <= 1.0) {
0921                 tmin = qMin(tmin, t1);
0922                 tmax = qMax(tmax, t1);
0923                 intersectionsFoundMax = true;
0924                 //debugFlake << "found intersection with dmax at " << t1 << "," << dmax;
0925             }
0926             qreal t2 = (dmin - n) / m;
0927             if (t2 >= 0.0 && t2 < 1.0) {
0928                 tmin = qMin(tmin, t2);
0929                 tmax = qMax(tmax, t2);
0930                 intersectionsFoundMin = true;
0931                 //debugFlake << "found intersection with dmin at " << t2 << "," << dmin;
0932             }
0933         }
0934     }
0935 
0936     bool intersectionsFound = intersectionsFoundMin && intersectionsFoundMax;
0937 
0938     //if (intersectionsFound)
0939     //    debugFlake << "clipping segment to interval [" << tmin << "," << tmax << "]";
0940 
0941     if (!intersectionsFound || (1.0 - (tmax - tmin)) <= 0.2) {
0942         //debugFlake << "could not clip enough -> split segment";
0943         // we could not reduce the interval significantly
0944         // so split the curve and calculate intersections
0945         // with the remaining parts
0946         QPair<KoPathSegment, KoPathSegment> parts = splitAt(0.5);
0947         if (d->chordLength() < 1e-5)
0948             isects += parts.first.second()->point();
0949         else {
0950             isects += segment.intersections(parts.first);
0951             isects += segment.intersections(parts.second);
0952         }
0953     } else if (qAbs(tmin - tmax) < 1e-5) {
0954         //debugFlake << "Yay, we found an intersection";
0955         // the inteval is pretty small now, just calculate the intersection at this point
0956         isects.append(segment.pointAt(tmin));
0957     } else {
0958         QPair<KoPathSegment, KoPathSegment> clip1 = segment.splitAt(tmin);
0959         //debugFlake << "splitting segment at" << tmin;
0960         qreal t = (tmax - tmin) / (1.0 - tmin);
0961         QPair<KoPathSegment, KoPathSegment> clip2 = clip1.second.splitAt(t);
0962         //debugFlake << "splitting second part at" << t << "("<<tmax<<")";
0963         isects += clip2.first.intersections(*this);
0964     }
0965 
0966     return isects;
0967 }
0968 
0969 KoPathSegment KoPathSegment::mapped(const QTransform &matrix) const
0970 {
0971     if (!isValid())
0972         return *this;
0973 
0974     KoPathPoint * p1 = new KoPathPoint(*d->first);
0975     KoPathPoint * p2 = new KoPathPoint(*d->second);
0976     p1->map(matrix);
0977     p2->map(matrix);
0978 
0979     return KoPathSegment(p1, p2);
0980 }
0981 
0982 KoPathSegment KoPathSegment::toCubic() const
0983 {
0984     if (! isValid())
0985         return KoPathSegment();
0986 
0987     KoPathPoint * p1 = new KoPathPoint(*d->first);
0988     KoPathPoint * p2 = new KoPathPoint(*d->second);
0989 
0990     if (degree() == 1) {
0991         p1->setControlPoint2(p1->point() + 0.3 * (p2->point() - p1->point()));
0992         p2->setControlPoint1(p2->point() + 0.3 * (p1->point() - p2->point()));
0993     } else if (degree() == 2) {
0994         /* quadric bezier (a0,a1,a2) to cubic bezier (b0,b1,b2,b3):
0995         *
0996         * b0 = a0
0997         * b1 = a0 + 2/3 * (a1-a0)
0998         * b2 = a1 + 1/3 * (a2-a1)
0999         * b3 = a2
1000         */
1001         QPointF a1 = p1->activeControlPoint2() ? p1->controlPoint2() : p2->controlPoint1();
1002         QPointF b1 = p1->point() + 2.0 / 3.0 * (a1 - p1->point());
1003         QPointF b2 = a1 + 1.0 / 3.0 * (p2->point() - a1);
1004         p1->setControlPoint2(b1);
1005         p2->setControlPoint1(b2);
1006     }
1007 
1008     return KoPathSegment(p1, p2);
1009 }
1010 
1011 qreal KoPathSegment::length(qreal error) const
1012 {
1013     /*
1014      * This algorithm is implemented based on an idea by Jens Gravesen:
1015      * "Adaptive subdivision and the length of Bezier curves" mat-report no. 1992-10, Mathematical Institute,
1016      * The Technical University of Denmark.
1017      *
1018      * By subdividing the curve at parameter value t you only have to find the length of a full Bezier curve.
1019      * If you denote the length of the control polygon by L1 i.e.:
1020      *   L1 = |P0 P1| +|P1 P2| +|P2 P3|
1021      *
1022      * and the length of the cord by L0 i.e.:
1023      *   L0 = |P0 P3|
1024      *
1025      * then
1026      *   L = 1/2*L0 + 1/2*L1
1027      *
1028      * is a good approximation to the length of the curve, and the difference
1029      *   ERR = L1-L0
1030      *
1031      * is a measure of the error. If the error is to large, then you just subdivide curve at parameter value
1032      * 1/2, and find the length of each half.
1033      * If m is the number of subdivisions then the error goes to zero as 2^-4m.
1034      * If you don't have a cubic curve but a curve of degree n then you put
1035      *   L = (2*L0 + (n-1)*L1)/(n+1)
1036      */
1037 
1038     int deg = degree();
1039 
1040     if (deg == -1)
1041         return 0.0;
1042 
1043     const QVector<QPointF> ctrlPoints = controlPoints();
1044 
1045     // calculate chord length
1046     qreal chordLen = d->chordLength();
1047 
1048     if (deg == 1) {
1049         return chordLen;
1050     }
1051 
1052     // calculate length of control polygon
1053     qreal polyLength = 0.0;
1054 
1055     for (int i = 0; i < deg; ++i) {
1056         QPointF ctrlSegment = ctrlPoints[i+1] - ctrlPoints[i];
1057         polyLength += sqrt(ctrlSegment.x() * ctrlSegment.x() + ctrlSegment.y() * ctrlSegment.y());
1058     }
1059 
1060     if ((polyLength - chordLen) > error) {
1061         // the error is still bigger than our tolerance -> split segment
1062         QPair<KoPathSegment, KoPathSegment> parts = splitAt(0.5);
1063         return parts.first.length(error) + parts.second.length(error);
1064     } else {
1065         // the error is smaller than our tolerance
1066         if (deg == 3)
1067             return 0.5 * chordLen + 0.5 * polyLength;
1068         else
1069             return (2.0 * chordLen + polyLength) / 3.0;
1070     }
1071 }
1072 
1073 qreal KoPathSegment::lengthAt(qreal t, qreal error) const
1074 {
1075     if (t == 0.0)
1076         return 0.0;
1077     if (t == 1.0)
1078         return length(error);
1079 
1080     QPair<KoPathSegment, KoPathSegment> parts = splitAt(t);
1081     return parts.first.length(error);
1082 }
1083 
1084 qreal KoPathSegment::paramAtLength(qreal length, qreal tolerance) const
1085 {
1086     const int deg = degree();
1087     // invalid degree or invalid specified length
1088     if (deg < 1 || length <= 0.0) {
1089         return 0.0;
1090     }
1091 
1092     if (deg == 1) {
1093         // make sure we return a maximum value of 1.0
1094         return qMin(qreal(1.0), length / d->chordLength());
1095     }
1096 
1097     // for curves we need to make sure, that the specified length
1098     // value does not exceed the actual length of the segment
1099     // if that happens, we return 1.0 to avoid infinite looping
1100     if (length >= d->chordLength() && length >= this->length(tolerance)) {
1101         return 1.0;
1102     }
1103 
1104     qreal startT = 0.0; // interval start
1105     qreal midT = 0.5;   // interval center
1106     qreal endT = 1.0;   // interval end
1107 
1108     // divide and conquer, split a midpoint and check
1109     // on which side of the midpoint to continue
1110     qreal midLength = lengthAt(0.5);
1111     while (qAbs(midLength - length) / length > tolerance) {
1112         if (midLength < length)
1113             startT = midT;
1114         else
1115             endT = midT;
1116 
1117         // new interval center
1118         midT = 0.5 * (startT + endT);
1119         // length at new interval center
1120         midLength = lengthAt(midT);
1121     }
1122 
1123     return midT;
1124 }
1125 
1126 bool KoPathSegment::isFlat(qreal tolerance) const
1127 {
1128     /*
1129      * Calculate the height of the bezier curve.
1130      * This is done by rotating the curve so that then chord
1131      * is parallel to the x-axis and the calculating the
1132      * parameters t for the extrema of the curve.
1133      * The curve points at the extrema are then used to
1134      * calculate the height.
1135      */
1136     if (degree() <= 1)
1137         return true;
1138 
1139     QPointF chord = d->second->point() - d->first->point();
1140     // calculate angle of chord to the x-axis
1141     qreal chordAngle = atan2(chord.y(), chord.x());
1142     QTransform m;
1143     m.translate(d->first->point().x(), d->first->point().y());
1144     m.rotate(chordAngle * M_PI / 180.0);
1145     m.translate(-d->first->point().x(), -d->first->point().y());
1146 
1147     KoPathSegment s = mapped(m);
1148 
1149     qreal minDist = 0.0;
1150     qreal maxDist = 0.0;
1151 
1152     for (qreal t : s.d->extrema()) {
1153         if (t >= 0.0 && t <= 1.0) {
1154             QPointF p = pointAt(t);
1155             qreal dist = s.d->distanceFromChord(p);
1156             minDist = qMin(dist, minDist);
1157             maxDist = qMax(dist, maxDist);
1158         }
1159     }
1160 
1161     return (maxDist - minDist <= tolerance);
1162 }
1163 
1164 QVector<QPointF> KoPathSegment::convexHull() const
1165 {
1166     QVector<QPointF> hull;
1167 
1168     int deg = degree();
1169     if (deg == 1) {
1170         // easy just the two end points
1171         hull.append(d->first->point());
1172         hull.append(d->second->point());
1173     } else if (deg == 2) {
1174         // we want to have a counter-clockwise oriented triangle
1175         // of the three control points
1176         QPointF chord = d->second->point() - d->first->point();
1177         QPointF cp = d->first->activeControlPoint2() ? d->first->controlPoint2() : d->second->controlPoint1();
1178         QPointF relP = cp - d->first->point();
1179         // check on which side of the chord the control point is
1180         bool pIsRight = (chord.x() * relP.y() - chord.y() * relP.x() > 0);
1181         hull.append(d->first->point());
1182         if (pIsRight)
1183             hull.append(cp);
1184         hull.append(d->second->point());
1185         if (! pIsRight)
1186             hull.append(cp);
1187     } else if (deg == 3) {
1188         // we want a counter-clockwise oriented polygon
1189         QPointF chord = d->second->point() - d->first->point();
1190         QPointF relP1 = d->first->controlPoint2() - d->first->point();
1191         // check on which side of the chord the control points are
1192         bool p1IsRight = (chord.x() * relP1.y() - chord.y() * relP1.x() > 0);
1193         hull.append(d->first->point());
1194         if (p1IsRight)
1195             hull.append(d->first->controlPoint2());
1196         hull.append(d->second->point());
1197         if (! p1IsRight)
1198             hull.append(d->first->controlPoint2());
1199 
1200         // now we have a counter-clockwise triangle with the points i,j,k
1201         // we have to check where the last control points lies
1202         bool rightOfEdge[3];
1203         QPointF lastPoint = d->second->controlPoint1();
1204         for (int i = 0; i < 3; ++i) {
1205             QPointF relP = lastPoint - hull[i];
1206             QPointF edge = hull[(i+1)%3] - hull[i];
1207             rightOfEdge[i] = (edge.x() * relP.y() - edge.y() * relP.x() > 0);
1208         }
1209         for (int i = 0; i < 3; ++i) {
1210             int prev = (3 + i - 1) % 3;
1211             int next = (i + 1) % 3;
1212             // check if point is only right of the n-th edge
1213             if (! rightOfEdge[prev] && rightOfEdge[i] && ! rightOfEdge[next]) {
1214                 // insert by breaking the n-th edge
1215                 hull.insert(i + 1, lastPoint);
1216                 break;
1217             }
1218             // check if it is right of the n-th and right of the (n+1)-th edge
1219             if (rightOfEdge[i] && rightOfEdge[next]) {
1220                 // remove both edge, insert two new edges
1221                 hull[i+1] = lastPoint;
1222                 break;
1223             }
1224             // check if it is right of n-th and right of (n-1)-th edge
1225             if (rightOfEdge[i] && rightOfEdge[prev]) {
1226                 hull[i] = lastPoint;
1227                 break;
1228             }
1229         }
1230     }
1231 
1232     return hull;
1233 }
1234 
1235 QPair<KoPathSegment, KoPathSegment> KoPathSegment::splitAt(qreal t) const
1236 {
1237     QPair<KoPathSegment, KoPathSegment> results;
1238     if (!isValid())
1239         return results;
1240 
1241     if (degree() == 1) {
1242         QPointF p = d->first->point() + t * (d->second->point() - d->first->point());
1243         results.first = KoPathSegment(d->first->point(), p);
1244         results.second = KoPathSegment(p, d->second->point());
1245     } else {
1246         QPointF newCP2, newCP1, splitP, splitCP1, splitCP2;
1247 
1248         d->deCasteljau(t, &newCP2, &splitCP1, &splitP, &splitCP2, &newCP1);
1249 
1250         if (degree() == 2) {
1251             if (second()->activeControlPoint1()) {
1252                 KoPathPoint *s1p1 = new KoPathPoint(0, d->first->point());
1253                 KoPathPoint *s1p2 = new KoPathPoint(0, splitP);
1254                 s1p2->setControlPoint1(splitCP1);
1255                 KoPathPoint *s2p1 = new KoPathPoint(0, splitP);
1256                 KoPathPoint *s2p2 = new KoPathPoint(0, d->second->point());
1257                 s2p2->setControlPoint1(splitCP2);
1258                 results.first = KoPathSegment(s1p1, s1p2);
1259                 results.second = KoPathSegment(s2p1, s2p2);
1260             } else {
1261                 results.first = KoPathSegment(d->first->point(), splitCP1, splitP);
1262                 results.second = KoPathSegment(splitP, splitCP2, d->second->point());
1263             }
1264         } else {
1265             results.first = KoPathSegment(d->first->point(), newCP2, splitCP1, splitP);
1266             results.second = KoPathSegment(splitP, splitCP2, newCP1, d->second->point());
1267         }
1268     }
1269 
1270     return results;
1271 }
1272 
1273 QVector<QPointF> KoPathSegment::controlPoints() const
1274 {
1275     QVector<QPointF> controlPoints;
1276 
1277     controlPoints.append(d->first->point());
1278     if (d->first->activeControlPoint2())
1279         controlPoints.append(d->first->controlPoint2());
1280     if (d->second->activeControlPoint1())
1281         controlPoints.append(d->second->controlPoint1());
1282     controlPoints.append(d->second->point());
1283 
1284     return controlPoints;
1285 }
1286 
1287 qreal KoPathSegment::nearestPoint(const QPointF &point) const
1288 {
1289     if (!isValid())
1290         return -1.0;
1291 
1292     const int deg = degree();
1293 
1294     // use shortcut for line segments
1295     if (deg == 1) {
1296         // the segments chord
1297         QPointF chord = d->second->point() - d->first->point();
1298         // the point relative to the segment
1299         QPointF relPoint = point - d->first->point();
1300         // project point to chord (dot product)
1301         qreal scale = chord.x() * relPoint.x() + chord.y() * relPoint.y();
1302         // normalize using the chord length
1303         scale /= chord.x() * chord.x() + chord.y() * chord.y();
1304 
1305         if (scale < 0.0) {
1306             return 0.0;
1307         } else if (scale > 1.0) {
1308             return 1.0;
1309         } else {
1310             return scale;
1311         }
1312     }
1313 
1314     /* This function solves the "nearest point on curve" problem. That means, it
1315     * calculates the point q (to be precise: it's parameter t) on this segment, which
1316     * is located nearest to the input point P.
1317     * The basic idea is best described (because it is freely available) in "Phoenix:
1318     * An Interactive Curve Design System Based on the Automatic Fitting of
1319     * Hand-Sketched Curves", Philip J. Schneider (Master thesis, University of
1320     * Washington).
1321     *
1322     * For the nearest point q = C(t) on this segment, the first derivative is
1323     * orthogonal to the distance vector "C(t) - P". In other words we are looking for
1324     * solutions of f(t) = (C(t) - P) * C'(t) = 0.
1325     * (C(t) - P) is a nth degree curve, C'(t) a n-1th degree curve => f(t) is a
1326     * (2n - 1)th degree curve and thus has up to 2n - 1 distinct solutions.
1327     * We solve the problem f(t) = 0 by using something called "Approximate Inversion Method".
1328     * Let's write f(t) explicitly (with c_i = p_i - P and d_j = p_{j+1} - p_j):
1329     *
1330     *         n                     n-1
1331     * f(t) = SUM c_i * B^n_i(t)  *  SUM d_j * B^{n-1}_j(t)
1332     *        i=0                    j=0
1333     *
1334     *         n  n-1
1335     *      = SUM SUM w_{ij} * B^{2n-1}_{i+j}(t)
1336     *        i=0 j=0
1337     *
1338     * with w_{ij} = c_i * d_j * z_{ij} and
1339     *
1340     *          BinomialCoeff(n, i) * BinomialCoeff(n - i ,j)
1341     * z_{ij} = -----------------------------------------------
1342     *                   BinomialCoeff(2n - 1, i + j)
1343     *
1344     * This Bernstein-Bezier polynom representation can now be solved for it's roots.
1345     */
1346 
1347     const QVector<QPointF> ctlPoints = controlPoints();
1348 
1349     // Calculate the c_i = point(i) - P.
1350     QPointF * c_i = new QPointF[ deg + 1 ];
1351 
1352     for (int i = 0; i <= deg; ++i) {
1353         c_i[ i ] = ctlPoints[ i ] - point;
1354     }
1355 
1356     // Calculate the d_j = point(j + 1) - point(j).
1357     QPointF *d_j = new QPointF[deg];
1358 
1359     for (int j = 0; j <= deg - 1; ++j) {
1360         d_j[j] = 3.0 * (ctlPoints[j+1] - ctlPoints[j]);
1361     }
1362 
1363     // Calculate the dot products of c_i and d_i.
1364     qreal *products = new qreal[deg * (deg + 1)];
1365 
1366     for (int j = 0; j <= deg - 1; ++j) {
1367         for (int i = 0; i <= deg; ++i) {
1368             products[j * (deg + 1) + i] = d_j[j].x() * c_i[i].x() + d_j[j].y() * c_i[i].y();
1369         }
1370     }
1371 
1372     // We don't need the c_i and d_i anymore.
1373     delete[] d_j ;
1374     delete[] c_i ;
1375 
1376     // Calculate the control points of the new 2n-1th degree curve.
1377     BezierSegment newCurve;
1378     newCurve.setDegree(2 * deg - 1);
1379     // Set up control points in the (u, f(u))-plane.
1380     for (unsigned short u = 0; u <= 2 * deg - 1; ++u) {
1381         newCurve.setPoint(u, QPointF(static_cast<qreal>(u) / static_cast<qreal>(2 * deg - 1), 0.0));
1382     }
1383 
1384     // Precomputed "z" for cubics
1385     static const qreal z3[3*4] = {1.0, 0.6, 0.3, 0.1, 0.4, 0.6, 0.6, 0.4, 0.1, 0.3, 0.6, 1.0};
1386     // Precomputed "z" for quadrics
1387     static const qreal z2[2*3] = {1.0, 2./3., 1./3., 1./3., 2./3., 1.0};
1388 
1389     const qreal *z = degree() == 3 ? z3 : z2;
1390 
1391     // Set f(u)-values.
1392     for (int k = 0; k <= 2 * deg - 1; ++k) {
1393         int min = qMin(k, deg);
1394 
1395         for (unsigned short i = qMax(0, k - (deg - 1)); i <= min; ++i) {
1396             unsigned short j = k - i;
1397 
1398             // p_k += products[j][i] * z[j][i].
1399             QPointF currentPoint = newCurve.point(k);
1400             currentPoint.ry() += products[j * (deg + 1) + i] * z[j * (deg + 1) + i];
1401             newCurve.setPoint(k, currentPoint);
1402         }
1403     }
1404 
1405     // We don't need the c_i/d_i dot products and the z_{ij} anymore.
1406     delete[] products;
1407 
1408     // Find roots.
1409     QList<qreal> rootParams = newCurve.roots();
1410 
1411     // Now compare the distances of the candidate points.
1412 
1413     // First candidate is the previous knot.
1414     QPointF dist = d->first->point() - point;
1415     qreal distanceSquared = dist.x() * dist.x() + dist.y() * dist.y();
1416     qreal oldDistanceSquared;
1417     qreal resultParam = 0.0;
1418 
1419     // Iterate over the found candidate params.
1420     for (qreal root : rootParams) {
1421         dist = point - pointAt(root);
1422         oldDistanceSquared = distanceSquared;
1423         distanceSquared = dist.x() * dist.x() + dist.y() * dist.y();
1424 
1425         if (distanceSquared < oldDistanceSquared)
1426             resultParam = root;
1427     }
1428 
1429     // Last candidate is the knot.
1430     dist = d->second->point() - point;
1431     oldDistanceSquared = distanceSquared;
1432     distanceSquared = dist.x() * dist.x() + dist.y() * dist.y();
1433 
1434     if (distanceSquared < oldDistanceSquared)
1435         resultParam = 1.0;
1436 
1437     return resultParam;
1438 }
1439 
1440 KoPathSegment KoPathSegment::interpolate(const QPointF &p0, const QPointF &p1, const QPointF &p2, qreal t)
1441 {
1442     if (t <= 0.0 || t >= 1.0)
1443         return KoPathSegment();
1444 
1445     /*
1446         B(t) = [x2 y2] = (1-t)^2*P0 + 2t*(1-t)*P1 + t^2*P2
1447 
1448                B(t) - (1-t)^2*P0 - t^2*P2
1449          P1 =  --------------------------
1450                        2t*(1-t)
1451     */
1452 
1453     QPointF c1 = p1 - (1.0-t) * (1.0-t)*p0 - t * t * p2;
1454 
1455     qreal denom = 2.0 * t * (1.0-t);
1456 
1457     c1.rx() /= denom;
1458     c1.ry() /= denom;
1459 
1460     return KoPathSegment(p0, c1, p2);
1461 }
1462 
1463 #if 0
1464 void KoPathSegment::printDebug() const
1465 {
1466     int deg = degree();
1467     debugFlake << "degree:" << deg;
1468     if (deg < 1)
1469         return;
1470 
1471     debugFlake << "P0:" << d->first->point();
1472     if (deg == 1) {
1473         debugFlake << "P2:" << d->second->point();
1474     } else if (deg == 2) {
1475         if (d->first->activeControlPoint2())
1476             debugFlake << "P1:" << d->first->controlPoint2();
1477         else
1478             debugFlake << "P1:" << d->second->controlPoint1();
1479         debugFlake << "P2:" << d->second->point();
1480     } else if (deg == 3) {
1481         debugFlake << "P1:" << d->first->controlPoint2();
1482         debugFlake << "P2:" << d->second->controlPoint1();
1483         debugFlake << "P3:" << d->second->point();
1484     }
1485 }
1486 #endif