File indexing completed on 2024-05-12 15:57:01

0001 /*
0002  *  SPDX-FileCopyrightText: 2008-2009 Jan Hambrecht <jaham@gmx.net>
0003  *  SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "KisBezierUtils.h"
0009 
0010 #include <tuple>
0011 #include <QStack>
0012 #include <QDebug>
0013 #include "kis_debug.h"
0014 
0015 #include "KisBezierPatch.h"
0016 #include <iostream>
0017 
0018 #include <config-gsl.h>
0019 
0020 #ifdef HAVE_GSL
0021 #include <gsl/gsl_multimin.h>
0022 #endif
0023 
0024 #include <Eigen/Dense>
0025 
0026 namespace KisBezierUtils
0027 {
0028 
0029 QVector<qreal> linearizeCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, const qreal eps)
0030 {
0031     const qreal minStepSize = 2.0 / kisDistance(p0, p3);
0032 
0033     QVector<qreal> steps;
0034     steps << 0.0;
0035 
0036 
0037     QStack<std::tuple<QPointF, QPointF, qreal>> stackedPoints;
0038     stackedPoints.push(std::make_tuple(p3, 3 * (p3 - p2), 1.0));
0039 
0040     QPointF lastP = p0;
0041     QPointF lastD = 3 * (p1 - p0);
0042     qreal lastT = 0.0;
0043 
0044     while (!stackedPoints.isEmpty()) {
0045         QPointF p = std::get<0>(stackedPoints.top());
0046         QPointF d = std::get<1>(stackedPoints.top());
0047         qreal t = std::get<2>(stackedPoints.top());
0048 
0049         if (t - lastT < minStepSize ||
0050                 isLinearSegmentByDerivatives(lastP, lastD, p, d, eps)) {
0051 
0052             lastP = p;
0053             lastD = d;
0054             lastT = t;
0055             steps << t;
0056             stackedPoints.pop();
0057         } else {
0058             t = 0.5 * (lastT + t);
0059             p = bezierCurve(p0, p1, p2, p3, t);
0060             d = bezierCurveDeriv(p0, p1, p2, p3, t);
0061 
0062             stackedPoints.push(std::make_tuple(p, d, t));
0063         }
0064     }
0065 
0066     return steps;
0067 }
0068 
0069 QVector<qreal> mergeLinearizationSteps(const QVector<qreal> &a, const QVector<qreal> &b)
0070 {
0071     QVector<qreal> result;
0072 
0073     std::merge(a.constBegin(), a.constEnd(),
0074                b.constBegin(), b.constEnd(),
0075                std::back_inserter(result));
0076     result.erase(
0077                 std::unique(result.begin(), result.end(),
0078                             [] (qreal x, qreal y) { return qFuzzyCompare(x, y); }),
0079             result.end());
0080 
0081     return result;
0082 }
0083 
0084 class BezierSegment
0085 {
0086 private:
0087     /// Maximal recursion depth for finding root params
0088     const int MaxRecursionDepth = 64;
0089     /// Flatness tolerance for finding root params
0090     const qreal FlatnessTolerance = ldexp(1.0,-MaxRecursionDepth-1);
0091 
0092 public:
0093     BezierSegment(int degree = 0, QPointF *p = 0)
0094     {
0095         if (degree) {
0096             for (int i = 0; i <= degree; ++i)
0097                 points.append(p[i]);
0098         }
0099     }
0100 
0101     void setDegree(int degree)
0102     {
0103         points.clear();
0104         if (degree) {
0105             for (int i = 0; i <= degree; ++i)
0106                 points.append(QPointF());
0107         }
0108     }
0109 
0110     int degree() const
0111     {
0112         return points.count() - 1;
0113     }
0114 
0115     QPointF point(int index) const
0116     {
0117         if (static_cast<int>(index) > degree())
0118             return QPointF();
0119 
0120         return points[index];
0121     }
0122 
0123     void setPoint(int index, const QPointF &p)
0124     {
0125         if (static_cast<int>(index) > degree())
0126             return;
0127 
0128         points[index] = p;
0129     }
0130 
0131     QPointF evaluate(qreal t, BezierSegment *left, BezierSegment *right) const
0132     {
0133         int deg = degree();
0134         if (! deg)
0135             return QPointF();
0136 
0137         QVector<QVector<QPointF> > Vtemp(deg + 1);
0138         for (int i = 0; i <= deg; ++i)
0139             Vtemp[i].resize(deg + 1);
0140 
0141         /* Copy control points  */
0142         for (int j = 0; j <= deg; j++) {
0143             Vtemp[0][j] = points[j];
0144         }
0145 
0146         /* Triangle computation */
0147         for (int i = 1; i <= deg; i++) {
0148             for (int j =0 ; j <= deg - i; j++) {
0149                 Vtemp[i][j].rx() = (1.0 - t) * Vtemp[i-1][j].x() + t * Vtemp[i-1][j+1].x();
0150                 Vtemp[i][j].ry() = (1.0 - t) * Vtemp[i-1][j].y() + t * Vtemp[i-1][j+1].y();
0151             }
0152         }
0153 
0154         if (left) {
0155             left->setDegree(deg);
0156             for (int j = 0; j <= deg; j++) {
0157                 left->setPoint(j, Vtemp[j][0]);
0158             }
0159         }
0160         if (right) {
0161             right->setDegree(deg);
0162             for (int j = 0; j <= deg; j++) {
0163                 right->setPoint(j, Vtemp[deg-j][j]);
0164             }
0165         }
0166 
0167         return (Vtemp[deg][0]);
0168     }
0169 
0170     QList<qreal> roots(int depth = 0) const
0171     {
0172         QList<qreal> rootParams;
0173 
0174         if (! degree())
0175             return rootParams;
0176 
0177         // Calculate how often the control polygon crosses the x-axis
0178         // This is the upper limit for the number of roots.
0179         int xAxisCrossings = controlPolygonZeros(points);
0180 
0181         if (! xAxisCrossings) {
0182             // No solutions.
0183             return rootParams;
0184         }
0185         else if (xAxisCrossings == 1) {
0186             // Exactly one solution.
0187 
0188             // Stop recursion when the tree is deep enough
0189             if (depth >= MaxRecursionDepth) {
0190                 // if deep enough, return 1 solution at midpoint
0191                 rootParams.append((points.first().x() + points.last().x()) / 2.0);
0192                 return rootParams;
0193             }
0194             else if (isFlat(FlatnessTolerance)) {
0195                 // Calculate intersection of chord with x-axis.
0196                 QPointF chord = points.last() - points.first();
0197                 QPointF segStart = points.first();
0198                 rootParams.append((chord.x() * segStart.y() - chord.y() * segStart.x()) / - chord.y());
0199                 return rootParams;
0200             }
0201         }
0202 
0203         // Many solutions. Do recursive midpoint subdivision.
0204         BezierSegment left, right;
0205         evaluate(0.5, &left, &right);
0206         rootParams += left.roots(depth+1);
0207         rootParams += right.roots(depth+1);
0208 
0209         return rootParams;
0210     }
0211 
0212     static uint controlPolygonZeros(const QList<QPointF> &controlPoints)
0213     {
0214         int controlPointCount = controlPoints.count();
0215         if (controlPointCount < 2)
0216             return 0;
0217 
0218         int signChanges = 0;
0219 
0220         int currSign = controlPoints[0].y() < 0.0 ? -1 : 1;
0221         int oldSign;
0222 
0223         for (short i = 1; i < controlPointCount; ++i) {
0224             oldSign = currSign;
0225             currSign = controlPoints[i].y() < 0.0 ? -1 : 1;
0226 
0227             if (currSign != oldSign) {
0228                 ++signChanges;
0229             }
0230         }
0231 
0232 
0233         return signChanges;
0234     }
0235 
0236     int isFlat (qreal tolerance) const
0237     {
0238         int deg = degree();
0239 
0240         // Find the  perpendicular distance from each interior control point to
0241         // the line connecting points[0] and points[degree]
0242         qreal *distance = new qreal[deg + 1];
0243 
0244         // Derive the implicit equation for line connecting first and last control points
0245         qreal a = points[0].y() - points[deg].y();
0246         qreal b = points[deg].x() - points[0].x();
0247         qreal c = points[0].x() * points[deg].y() - points[deg].x() * points[0].y();
0248 
0249         qreal abSquared = (a * a) + (b * b);
0250 
0251         for (int i = 1; i < deg; i++) {
0252             // Compute distance from each of the points to that line
0253             distance[i] = a * points[i].x() + b * points[i].y() + c;
0254             if (distance[i] > 0.0) {
0255                 distance[i] = (distance[i] * distance[i]) / abSquared;
0256             }
0257             if (distance[i] < 0.0) {
0258                 distance[i] = -((distance[i] * distance[i]) / abSquared);
0259             }
0260         }
0261 
0262 
0263         // Find the largest distance
0264         qreal max_distance_above = 0.0;
0265         qreal max_distance_below = 0.0;
0266         for (int i = 1; i < deg; i++) {
0267             if (distance[i] < 0.0) {
0268                 max_distance_below = qMin(max_distance_below, distance[i]);
0269             }
0270             if (distance[i] > 0.0) {
0271                 max_distance_above = qMax(max_distance_above, distance[i]);
0272             }
0273         }
0274         delete [] distance;
0275 
0276         // Implicit equation for zero line
0277         qreal a1 = 0.0;
0278         qreal b1 = 1.0;
0279         qreal c1 = 0.0;
0280 
0281         // Implicit equation for "above" line
0282         qreal a2 = a;
0283         qreal b2 = b;
0284         qreal c2 = c + max_distance_above;
0285 
0286         qreal det = a1 * b2 - a2 * b1;
0287         qreal dInv = 1.0/det;
0288 
0289         qreal intercept_1 = (b1 * c2 - b2 * c1) * dInv;
0290 
0291         // Implicit equation for "below" line
0292         a2 = a;
0293         b2 = b;
0294         c2 = c + max_distance_below;
0295 
0296         det = a1 * b2 - a2 * b1;
0297         dInv = 1.0/det;
0298 
0299         qreal intercept_2 = (b1 * c2 - b2 * c1) * dInv;
0300 
0301         // Compute intercepts of bounding box
0302         qreal left_intercept = qMin(intercept_1, intercept_2);
0303         qreal right_intercept = qMax(intercept_1, intercept_2);
0304 
0305         qreal error = 0.5 * (right_intercept-left_intercept);
0306 
0307         return (error < tolerance);
0308     }
0309 
0310 #ifndef NDEBUG
0311     void printDebug() const
0312     {
0313         int index = 0;
0314         Q_FOREACH (const QPointF &p, points) {
0315             qDebug() << QString("P%1 ").arg(index++) << p;
0316         }
0317     }
0318 #endif
0319 
0320 private:
0321     QList<QPointF> points;
0322 };
0323 
0324 qreal nearestPoint(const QList<QPointF> controlPoints, const QPointF &point, qreal *resultDistance, QPointF *resultPoint)
0325 {
0326     const int deg = controlPoints.size() - 1;
0327 
0328     // use shortcut for line segments
0329     if (deg == 1) {
0330         // the segments chord
0331         QPointF chord = controlPoints.last() - controlPoints.first();
0332         // the point relative to the segment
0333         QPointF relPoint = point - controlPoints.first();
0334         // project point to chord (dot product)
0335         qreal scale = chord.x() * relPoint.x() + chord.y() * relPoint.y();
0336         // normalize using the chord length
0337         scale /= chord.x() * chord.x() + chord.y() * chord.y();
0338 
0339         if (scale < 0.0) {
0340             return 0.0;
0341         } else if (scale > 1.0) {
0342             return 1.0;
0343         } else {
0344             return scale;
0345         }
0346     }
0347 
0348     /* This function solves the "nearest point on curve" problem. That means, it
0349     * calculates the point q (to be precise: it's parameter t) on this segment, which
0350     * is located nearest to the input point P.
0351     * The basic idea is best described (because it is freely available) in "Phoenix:
0352     * An Interactive Curve Design System Based on the Automatic Fitting of
0353     * Hand-Sketched Curves", Philip J. Schneider (Master thesis, University of
0354     * Washington).
0355     *
0356     * For the nearest point q = C(t) on this segment, the first derivative is
0357     * orthogonal to the distance vector "C(t) - P". In other words we are looking for
0358     * solutions of f(t) = (C(t) - P) * C'(t) = 0.
0359     * (C(t) - P) is a nth degree curve, C'(t) a n-1th degree curve => f(t) is a
0360     * (2n - 1)th degree curve and thus has up to 2n - 1 distinct solutions.
0361     * We solve the problem f(t) = 0 by using something called "Approximate Inversion Method".
0362     * Let's write f(t) explicitly (with c_i = p_i - P and d_j = p_{j+1} - p_j):
0363     *
0364     *         n                     n-1
0365     * f(t) = SUM c_i * B^n_i(t)  *  SUM d_j * B^{n-1}_j(t)
0366     *        i=0                    j=0
0367     *
0368     *         n  n-1
0369     *      = SUM SUM w_{ij} * B^{2n-1}_{i+j}(t)
0370     *        i=0 j=0
0371     *
0372     * with w_{ij} = c_i * d_j * z_{ij} and
0373     *
0374     *          BinomialCoeff(n, i) * BinomialCoeff(n - i ,j)
0375     * z_{ij} = -----------------------------------------------
0376     *                   BinomialCoeff(2n - 1, i + j)
0377     *
0378     * This Bernstein-Bezier polynom representation can now be solved for its roots.
0379     */
0380 
0381     QList<QPointF> ctlPoints = controlPoints;
0382 
0383     // Calculate the c_i = point(i) - P.
0384     QPointF * c_i = new QPointF[ deg + 1 ];
0385 
0386     for (int i = 0; i <= deg; ++i) {
0387         c_i[ i ] = ctlPoints[ i ] - point;
0388     }
0389 
0390     // Calculate the d_j = point(j + 1) - point(j).
0391     QPointF *d_j = new QPointF[deg];
0392 
0393     for (int j = 0; j <= deg - 1; ++j) {
0394         d_j[j] = 3.0 * (ctlPoints[j+1] - ctlPoints[j]);
0395     }
0396 
0397     // Calculate the dot products of c_i and d_i.
0398     qreal *products = new qreal[deg * (deg + 1)];
0399 
0400     for (int j = 0; j <= deg - 1; ++j) {
0401         for (int i = 0; i <= deg; ++i) {
0402             products[j * (deg + 1) + i] = d_j[j].x() * c_i[i].x() + d_j[j].y() * c_i[i].y();
0403         }
0404     }
0405 
0406     // We don't need the c_i and d_i anymore.
0407     delete[] d_j ;
0408     delete[] c_i ;
0409 
0410     // Calculate the control points of the new 2n-1th degree curve.
0411     BezierSegment newCurve;
0412     newCurve.setDegree(2 * deg - 1);
0413     // Set up control points in the (u, f(u))-plane.
0414     for (unsigned short u = 0; u <= 2 * deg - 1; ++u) {
0415         newCurve.setPoint(u, QPointF(static_cast<qreal>(u) / static_cast<qreal>(2 * deg - 1), 0.0));
0416     }
0417 
0418     // Precomputed "z" for cubics
0419     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};
0420     // Precomputed "z" for quadrics
0421     static const qreal z2[2*3] = {1.0, 2./3., 1./3., 1./3., 2./3., 1.0};
0422 
0423     const qreal *z = deg == 3 ? z3 : z2;
0424 
0425     // Set f(u)-values.
0426     for (int k = 0; k <= 2 * deg - 1; ++k) {
0427         int min = qMin(k, deg);
0428 
0429         for (unsigned short i = qMax(0, k - (deg - 1)); i <= min; ++i) {
0430             unsigned short j = k - i;
0431 
0432             // p_k += products[j][i] * z[j][i].
0433             QPointF currentPoint = newCurve.point(k);
0434             currentPoint.ry() += products[j * (deg + 1) + i] * z[j * (deg + 1) + i];
0435             newCurve.setPoint(k, currentPoint);
0436         }
0437     }
0438 
0439     // We don't need the c_i/d_i dot products and the z_{ij} anymore.
0440     delete[] products;
0441 
0442     // Find roots.
0443     QList<qreal> rootParams = newCurve.roots();
0444 
0445     // Now compare the distances of the candidate points.
0446 
0447     // First candidate is the previous knot.
0448     qreal distanceSquared = kisSquareDistance(point, controlPoints.first());
0449     qreal minDistanceSquared = distanceSquared;
0450     qreal resultParam = 0.0;
0451     if (resultDistance) {
0452         *resultDistance = std::sqrt(distanceSquared);
0453     }
0454     if (resultPoint) {
0455         *resultPoint = controlPoints.first();
0456     }
0457 
0458     // Iterate over the found candidate params.
0459     Q_FOREACH (qreal root, rootParams) {
0460         const QPointF rootPoint = bezierCurve(controlPoints, root);
0461         distanceSquared = kisSquareDistance(point, rootPoint);
0462 
0463         if (distanceSquared < minDistanceSquared) {
0464             minDistanceSquared = distanceSquared;
0465             resultParam = root;
0466             if (resultDistance) {
0467                 *resultDistance = std::sqrt(distanceSquared);
0468             }
0469             if (resultPoint) {
0470                 *resultPoint = rootPoint;
0471             }
0472         }
0473     }
0474 
0475     // Last candidate is the knot.
0476     distanceSquared = kisSquareDistance(point, controlPoints.last());
0477     if (distanceSquared < minDistanceSquared) {
0478         minDistanceSquared = distanceSquared;
0479         resultParam = 1.0;
0480         if (resultDistance) {
0481             *resultDistance = std::sqrt(distanceSquared);
0482         }
0483         if (resultPoint) {
0484             *resultPoint = controlPoints.last();
0485         }
0486     }
0487 
0488     return resultParam;
0489 }
0490 
0491 int controlPolygonZeros(const QList<QPointF> &controlPoints)
0492 {
0493     return static_cast<int>(BezierSegment::controlPolygonZeros(controlPoints));
0494 }
0495 
0496 namespace {
0497 
0498 struct Params2D {
0499     QPointF p0, p1, p2, p3; // top curve
0500     QPointF q0, q1, q2, q3; // bottom curve
0501     QPointF r0, r1, r2, r3; // left curve
0502     QPointF s0, s1, s2, s3; // right curve
0503 
0504     QPointF dstPoint;
0505 };
0506 
0507 struct LevelBasedPatchMethod
0508 {
0509     LevelBasedPatchMethod(qreal u, qreal v, const Params2D &p)
0510     {
0511         M_3 << 1, 0, 0, 0,
0512              -3, 3, 0, 0,
0513               3, -6, 3, 0,
0514              -1, 3, -3, 1;
0515 
0516         M_3rel2abs << 1, 0, 0, 0,
0517                       1, 1, 0, 0,
0518                       0, 0, 1, 1,
0519                       0, 0, 0, 1;
0520 
0521         M_1 << -1,  1,  0, 0,
0522                 1, -1, -1, 1;
0523 
0524         PQ_left << p.p0.x(), p.p0.y(),
0525                    p.p1.x(), p.p1.y(),
0526                    p.q0.x(), p.q0.y(),
0527                    p.q1.x(), p.q1.y();
0528 
0529         PQ_right << p.p3.x(), p.p3.y(),
0530                     p.p2.x(), p.p2.y(),
0531                     p.q3.x(), p.q3.y(),
0532                     p.q2.x(), p.q2.y();
0533 
0534         RS_top << p.r0.x(), p.r0.y(),
0535                   p.r1.x(), p.r1.y(),
0536                   p.s0.x(), p.s0.y(),
0537                   p.s1.x(), p.s1.y();
0538 
0539         RS_bottom << p.r3.x(), p.r3.y(),
0540                      p.r2.x(), p.r2.y(),
0541                      p.s3.x(), p.s3.y(),
0542                      p.s2.x(), p.s2.y();
0543 
0544         R << p.r0.x(), p.r0.y(),
0545              p.r1.x(), p.r1.y(),
0546              p.r2.x(), p.r2.y(),
0547              p.r3.x(), p.r3.y();
0548 
0549         S << p.s0.x(), p.s0.y(),
0550              p.s1.x(), p.s1.y(),
0551              p.s2.x(), p.s2.y(),
0552              p.s3.x(), p.s3.y();
0553 
0554         P << p.p0.x(), p.p0.y(),
0555              p.p1.x(), p.p1.y(),
0556              p.p2.x(), p.p2.y(),
0557              p.p3.x(), p.p3.y();
0558 
0559         Q << p.q0.x(), p.q0.y(),
0560              p.q1.x(), p.q1.y(),
0561              p.q2.x(), p.q2.y(),
0562              p.q3.x(), p.q3.y();
0563 
0564         T_u3 << 1, u, pow2(u), pow3(u);
0565         T_v3 << 1, v, pow2(v), pow3(v);
0566         T_dot_u3 << 0, 1, 2 * u, 3 * pow2(u);
0567         T_dot_v3 << 0, 1, 2 * v, 3 * pow2(v);
0568 
0569         T_u1 << 1, u;
0570         T_v1 << 1, v;
0571         T_dot_u1 << 0, 1;
0572         T_dot_v1 << 0, 1;
0573     }
0574 
0575     Eigen::Matrix4d M_3;
0576     Eigen::Matrix4d M_3rel2abs;
0577     Eigen::Matrix<double, 2, 4> M_1;
0578 
0579 
0580     Eigen::Matrix<double, 4, 2> PQ_left;
0581     Eigen::Matrix<double, 4, 2> PQ_right;
0582     Eigen::Matrix<double, 4, 2> RS_top;
0583     Eigen::Matrix<double, 4, 2> RS_bottom;
0584 
0585     Eigen::Matrix<double, 4, 2> R;
0586     Eigen::Matrix<double, 4, 2> S;
0587     Eigen::Matrix<double, 4, 2> P;
0588     Eigen::Matrix<double, 4, 2> Q;
0589 
0590     Eigen::Matrix<double, 1, 4> T_u3;
0591     Eigen::Matrix<double, 1, 4> T_v3;
0592     Eigen::Matrix<double, 1, 4> T_dot_u3;
0593     Eigen::Matrix<double, 1, 4> T_dot_v3;
0594 
0595     Eigen::Matrix<double, 1, 2> T_u1;
0596     Eigen::Matrix<double, 1, 2> T_v1;
0597     Eigen::Matrix<double, 1, 2> T_dot_u1;
0598     Eigen::Matrix<double, 1, 2> T_dot_v1;
0599 
0600     QPointF value() const {
0601         Eigen::Matrix<double, 1, 2> L_1 = T_v3 * M_3 * R;
0602         Eigen::Matrix<double, 1, 2> L_2 = T_v1 * M_1 * PQ_left;
0603         Eigen::Matrix<double, 1, 2> L_3 = T_v1 * M_1 * PQ_right;
0604         Eigen::Matrix<double, 1, 2> L_4 = T_v3 * M_3 * S;
0605 
0606         Eigen::Matrix<double, 4, 2> L_controls;
0607         L_controls << L_1, L_2, L_3, L_4;
0608 
0609         Eigen::Matrix<double, 1, 2> L = T_u3 * M_3 * M_3rel2abs * L_controls;
0610 
0611 
0612         Eigen::Matrix<double, 1, 2> H_1 = T_u3 * M_3 * P;
0613         Eigen::Matrix<double, 1, 2> H_2 = T_u1 * M_1 * RS_top;
0614         Eigen::Matrix<double, 1, 2> H_3 = T_u1 * M_1 * RS_bottom;
0615         Eigen::Matrix<double, 1, 2> H_4 = T_u3 * M_3 * Q;
0616 
0617         Eigen::Matrix<double, 4, 2> H_controls;
0618         H_controls << H_1, H_2, H_3, H_4;
0619 
0620         Eigen::Matrix<double, 1, 2> H = T_v3 * M_3 * M_3rel2abs * H_controls;
0621 
0622         Eigen::Matrix<double, 1, 2> result = 0.5 * (L + H);
0623 
0624         return QPointF(result(0,0), result(0,1));
0625     }
0626 
0627     QPointF diffU() const {
0628         Eigen::Matrix<double, 1, 2> L_1 = T_v3 * M_3 * R;
0629         Eigen::Matrix<double, 1, 2> L_2 = T_v1 * M_1 * PQ_left;
0630         Eigen::Matrix<double, 1, 2> L_3 = T_v1 * M_1 * PQ_right;
0631         Eigen::Matrix<double, 1, 2> L_4 = T_v3 * M_3 * S;
0632 
0633         Eigen::Matrix<double, 4, 2> L_controls;
0634         L_controls << L_1, L_2, L_3, L_4;
0635 
0636         Eigen::Matrix<double, 1, 2> L = T_dot_u3 * M_3 * M_3rel2abs * L_controls;
0637 
0638 
0639         Eigen::Matrix<double, 1, 2> H_1 = T_dot_u3 * M_3 * P;
0640         Eigen::Matrix<double, 1, 2> H_2 = T_dot_u1 * M_1 * RS_top;
0641         Eigen::Matrix<double, 1, 2> H_3 = T_dot_u1 * M_1 * RS_bottom;
0642         Eigen::Matrix<double, 1, 2> H_4 = T_dot_u3 * M_3 * Q;
0643 
0644         Eigen::Matrix<double, 4, 2> H_controls;
0645         H_controls << H_1, H_2, H_3, H_4;
0646 
0647         Eigen::Matrix<double, 1, 2> H = T_v3 * M_3 * M_3rel2abs * H_controls;
0648 
0649         Eigen::Matrix<double, 1, 2> result = 0.5 * (L + H);
0650         return QPointF(result(0,0), result(0,1));
0651     }
0652 
0653     QPointF diffV() const {
0654         Eigen::Matrix<double, 1, 2> L_1 = T_dot_v3 * M_3 * R;
0655         Eigen::Matrix<double, 1, 2> L_2 = T_dot_v1 * M_1 * PQ_left;
0656         Eigen::Matrix<double, 1, 2> L_3 = T_dot_v1 * M_1 * PQ_right;
0657         Eigen::Matrix<double, 1, 2> L_4 = T_dot_v3 * M_3 * S;
0658 
0659         Eigen::Matrix<double, 4, 2> L_controls;
0660         L_controls << L_1, L_2, L_3, L_4;
0661 
0662         Eigen::Matrix<double, 1, 2> L = T_u3 * M_3 * M_3rel2abs * L_controls;
0663 
0664         Eigen::Matrix<double, 1, 2> H_1 = T_u3 * M_3 * P;
0665         Eigen::Matrix<double, 1, 2> H_2 = T_u1 * M_1 * RS_top;
0666         Eigen::Matrix<double, 1, 2> H_3 = T_u1 * M_1 * RS_bottom;
0667         Eigen::Matrix<double, 1, 2> H_4 = T_u3 * M_3 * Q;
0668 
0669         Eigen::Matrix<double, 4, 2> H_controls;
0670         H_controls << H_1, H_2, H_3, H_4;
0671 
0672         Eigen::Matrix<double, 1, 2> H = T_dot_v3 * M_3 * M_3rel2abs * H_controls;
0673 
0674         Eigen::Matrix<double, 1, 2> result = 0.5 * (L + H);
0675 
0676         return QPointF(result(0,0), result(0,1));
0677     }
0678 
0679 };
0680 
0681 struct SvgPatchMethod
0682 {
0683 private:
0684 
0685     /**
0686      * TODO: optimize these function somehow!
0687      */
0688 
0689     static QPointF meshForwardMapping(qreal u, qreal v, const Params2D &p) {
0690         return p.r0 + pow3(u)*v*(p.p0 - 3*p.p1 + 3*p.p2 - p.p3 - p.q0 + 3*p.q1 - 3*p.q2 + p.q3) + pow3(u)*(-p.p0 + 3*p.p1 - 3*p.p2 + p.p3) + pow2(u)*v*(-3*p.p0 + 6*p.p1 - 3*p.p2 + 3*p.q0 - 6*p.q1 + 3*p.q2) + pow2(u)*(3*p.p0 - 6*p.p1 + 3*p.p2) + u*pow3(v)*(p.r0 - 3*p.r1 + 3*p.r2 - p.r3 - p.s0 + 3*p.s1 - 3*p.s2 + p.s3) + u*pow2(v)*(-3*p.r0 + 6*p.r1 - 3*p.r2 + 3*p.s0 - 6*p.s1+ 3*p.s2) + u*v*(2*p.p0 - 3*p.p1 + p.p3 - 2*p.q0 + 3*p.q1 - p.q3 + 3*p.r0 - 3*p.r1 - 3*p.s0 + 3*p.s1) + u*(-2*p.p0 + 3*p.p1 - p.p3 - p.r0 + p.s0) + pow3(v)*(-p.r0 + 3*p.r1 - 3*p.r2 + p.r3) + pow2(v)*(3*p.r0 - 6*p.r1 + 3*p.r2) + v*(-3*p.r0 + 3*p.r1);
0691     }
0692 
0693     static QPointF meshForwardMappingDiffU(qreal u, qreal v, const Params2D &p) {
0694         return -2*p.p0 + 3*p.p1 - p.p3 - p.r0 + p.s0 + pow2(u)*v*(3*p.p0 - 9*p.p1 + 9*p.p2 - 3*p.p3 - 3*p.q0 + 9*p.q1 - 9*p.q2 + 3*p.q3) + pow2(u)*(-3*p.p0 + 9*p.p1 - 9*p.p2 + 3*p.p3) + u*v*(-6*p.p0 + 12*p.p1 - 6*p.p2 + 6*p.q0 - 12*p.q1 + 6*p.q2) + u*(6*p.p0 - 12*p.p1 + 6*p.p2) + pow3(v)*(p.r0 - 3*p.r1 + 3*p.r2 - p.r3 - p.s0 + 3*p.s1 - 3*p.s2 + p.s3) + pow2(v)*(-3*p.r0 + 6*p.r1 - 3*p.r2 + 3*p.s0 - 6*p.s1 + 3*p.s2) + v*(2*p.p0 - 3*p.p1 + p.p3 - 2*p.q0 + 3*p.q1 - p.q3 + 3*p.r0 - 3*p.r1 - 3*p.s0 + 3*p.s1);
0695     }
0696 
0697     static QPointF meshForwardMappingDiffV(qreal u, qreal v, const Params2D &p) {
0698         return -3*p.r0 + 3*p.r1 + pow3(u)*(p.p0 - 3*p.p1 + 3*p.p2 - p.p3 - p.q0 + 3*p.q1 - 3*p.q2 + p.q3) + pow2(u)*(-3*p.p0 + 6*p.p1 - 3*p.p2 + 3*p.q0 - 6*p.q1 + 3*p.q2) + u*pow2(v)*(3*p.r0 - 9*p.r1 + 9*p.r2 - 3*p.r3 - 3*p.s0 + 9*p.s1 - 9*p.s2 + 3*p.s3) + u*v*(-6*p.r0 + 12*p.r1 - 6*p.r2 + 6*p.s0 - 12*p.s1 + 6*p.s2) + u*(2*p.p0 - 3*p.p1 + p.p3 - 2*p.q0 + 3*p.q1 - p.q3 + 3*p.r0 - 3*p.r1 - 3*p.s0 + 3*p.s1) + pow2(v)*(-3*p.r0 + 9*p.r1 - 9*p.r2 + 3*p.r3) + v*(6*p.r0 - 12*p.r1 + 6*p.r2);
0699     }
0700 
0701     qreal u = 0.0;
0702     qreal v = 0.0;
0703     const Params2D p;
0704 
0705 public:
0706     SvgPatchMethod(qreal _u, qreal _v, const Params2D &_p)
0707         : u(_u), v(_v), p(_p)
0708     {
0709     }
0710 
0711     QPointF value() const {
0712         return meshForwardMapping(u, v, p);
0713     }
0714 
0715     QPointF diffU() const {
0716         return meshForwardMappingDiffU(u, v, p);
0717     }
0718 
0719     QPointF diffV() const {
0720         return meshForwardMappingDiffV(u, v, p);
0721     }
0722 
0723 };
0724 
0725 template <class PatchMethod>
0726 double my_f(const gsl_vector * x, void *paramsPtr)
0727 {
0728     const Params2D *params = static_cast<const Params2D*>(paramsPtr);
0729     const QPointF pos(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
0730 
0731     PatchMethod mat(pos.x(), pos.y(), *params);
0732     const QPointF S = mat.value();
0733 
0734     return kisSquareDistance(S, params->dstPoint);
0735 }
0736 
0737 template <class PatchMethod>
0738 void my_fdf (const gsl_vector *x, void *paramsPtr, double *f, gsl_vector *df)
0739 {
0740     const Params2D *params = static_cast<const Params2D*>(paramsPtr);
0741     const QPointF pos(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
0742 
0743     PatchMethod mat(pos.x(), pos.y(), *params);
0744     const QPointF S = mat.value();
0745     const QPointF dU = mat.diffU();
0746     const QPointF dV = mat.diffV();
0747 
0748     *f = kisSquareDistance(S, params->dstPoint);
0749 
0750     gsl_vector_set(df, 0,
0751                    2 * (S.x() - params->dstPoint.x()) * dU.x() +
0752                    2 * (S.y() - params->dstPoint.y()) * dU.y());
0753     gsl_vector_set(df, 1,
0754                    2 * (S.x() - params->dstPoint.x()) * dV.x() +
0755                    2 * (S.y() - params->dstPoint.y()) * dV.y());
0756 }
0757 
0758 template <class PatchMethod>
0759 void my_df (const gsl_vector *x, void *paramsPtr,
0760             gsl_vector *df)
0761 {
0762     const Params2D *params = static_cast<const Params2D*>(paramsPtr);
0763     const QPointF pos(gsl_vector_get(x, 0), gsl_vector_get(x, 1));
0764 
0765     PatchMethod mat(pos.x(), pos.y(), *params);
0766     const QPointF S = mat.value();
0767     const QPointF dU = mat.diffU();
0768     const QPointF dV = mat.diffV();
0769 
0770     gsl_vector_set(df, 0,
0771                    2 * (S.x() - params->dstPoint.x()) * dU.x() +
0772                    2 * (S.y() - params->dstPoint.y()) * dU.y());
0773     gsl_vector_set(df, 1,
0774                    2 * (S.x() - params->dstPoint.x()) * dV.x() +
0775                    2 * (S.y() - params->dstPoint.y()) * dV.y());
0776 }
0777 }
0778 
0779 template <class PatchMethod>
0780 QPointF calculateLocalPosImpl(const std::array<QPointF, 12> &points, const QPointF &globalPoint)
0781 {
0782     QRectF patchBounds;
0783 
0784     for (auto it = points.begin(); it != points.end(); ++it) {
0785         KisAlgebra2D::accumulateBounds(*it, &patchBounds);
0786     }
0787 
0788     const QPointF approxStart = KisAlgebra2D::absoluteToRelative(globalPoint, patchBounds);
0789     KIS_SAFE_ASSERT_RECOVER_NOOP(QRectF(0,0,1.0,1.0).contains(approxStart));
0790 
0791 #ifdef HAVE_GSL
0792     const gsl_multimin_fdfminimizer_type *T =
0793         gsl_multimin_fdfminimizer_vector_bfgs2;
0794     gsl_multimin_fdfminimizer *s = 0;
0795     gsl_vector *x;
0796     gsl_multimin_function_fdf minex_func;
0797 
0798     size_t iter = 0;
0799     int status;
0800 
0801     /* Starting point */
0802     x = gsl_vector_alloc (2);
0803     gsl_vector_set (x, 0, approxStart.x());
0804     gsl_vector_set (x, 1, approxStart.y());
0805 
0806     Params2D p;
0807 
0808     p.p0 = points[KisBezierPatch::TL];
0809     p.p1 = points[KisBezierPatch::TL_HC];
0810     p.p2 = points[KisBezierPatch::TR_HC];
0811     p.p3 = points[KisBezierPatch::TR];
0812 
0813     p.q0 = points[KisBezierPatch::BL];
0814     p.q1 = points[KisBezierPatch::BL_HC];
0815     p.q2 = points[KisBezierPatch::BR_HC];
0816     p.q3 = points[KisBezierPatch::BR];
0817 
0818     p.r0 = points[KisBezierPatch::TL];
0819     p.r1 = points[KisBezierPatch::TL_VC];
0820     p.r2 = points[KisBezierPatch::BL_VC];
0821     p.r3 = points[KisBezierPatch::BL];
0822 
0823     p.s0 = points[KisBezierPatch::TR];
0824     p.s1 = points[KisBezierPatch::TR_VC];
0825     p.s2 = points[KisBezierPatch::BR_VC];
0826     p.s3 = points[KisBezierPatch::BR];
0827 
0828     p.dstPoint = globalPoint;
0829 
0830     /* Initialize method and iterate */
0831     minex_func.n = 2;
0832     minex_func.f = my_f<PatchMethod>;
0833     minex_func.params = (void*)&p;
0834     minex_func.df = my_df<PatchMethod>;
0835     minex_func.fdf = my_fdf<PatchMethod>;
0836 
0837     s = gsl_multimin_fdfminimizer_alloc (T, 2);
0838     gsl_multimin_fdfminimizer_set (s, &minex_func, x, 0.01, 0.1);
0839 
0840     QPointF result;
0841 
0842 
0843     result.rx() = gsl_vector_get (s->x, 0);
0844     result.ry() = gsl_vector_get (s->x, 1);
0845 
0846     do
0847     {
0848         iter++;
0849         status = gsl_multimin_fdfminimizer_iterate(s);
0850 
0851         if (status)
0852             break;
0853 
0854         status = gsl_multimin_test_gradient (s->gradient, 1e-4);
0855 
0856         result.rx() = gsl_vector_get (s->x, 0);
0857         result.ry() = gsl_vector_get (s->x, 1);
0858 
0859         if (status == GSL_SUCCESS)
0860         {
0861             result.rx() = gsl_vector_get (s->x, 0);
0862             result.ry() = gsl_vector_get (s->x, 1);
0863             //qDebug() << "******* Converged to minimum" << ppVar(result);
0864 
0865         }
0866     }
0867     while (status == GSL_CONTINUE && iter < 10000);
0868 
0869 //    ENTER_FUNCTION()<< ppVar(iter) << ppVar(globalPoint) << ppVar(result);
0870 //    ENTER_FUNCTION() << ppVar(meshForwardMapping(result.x(), result.y(), p));
0871 
0872     gsl_vector_free(x);
0873     gsl_multimin_fdfminimizer_free (s);
0874 
0875     return result;
0876 #else
0877     return approxStart;
0878 #endif
0879 }
0880 
0881 template <class PatchMethod>
0882 QPointF calculateGlobalPosImpl(const std::array<QPointF, 12> &points, const QPointF &localPoint)
0883 {
0884     Params2D p;
0885 
0886     p.p0 = points[KisBezierPatch::TL];
0887     p.p1 = points[KisBezierPatch::TL_HC];
0888     p.p2 = points[KisBezierPatch::TR_HC];
0889     p.p3 = points[KisBezierPatch::TR];
0890 
0891     p.q0 = points[KisBezierPatch::BL];
0892     p.q1 = points[KisBezierPatch::BL_HC];
0893     p.q2 = points[KisBezierPatch::BR_HC];
0894     p.q3 = points[KisBezierPatch::BR];
0895 
0896     p.r0 = points[KisBezierPatch::TL];
0897     p.r1 = points[KisBezierPatch::TL_VC];
0898     p.r2 = points[KisBezierPatch::BL_VC];
0899     p.r3 = points[KisBezierPatch::BL];
0900 
0901     p.s0 = points[KisBezierPatch::TR];
0902     p.s1 = points[KisBezierPatch::TR_VC];
0903     p.s2 = points[KisBezierPatch::BR_VC];
0904     p.s3 = points[KisBezierPatch::BR];
0905 
0906     PatchMethod f(localPoint.x(), localPoint.y(), p);
0907     return f.value();
0908 }
0909 
0910 QPointF calculateLocalPos(const std::array<QPointF, 12> &points, const QPointF &globalPoint)
0911 {
0912    return calculateLocalPosImpl<LevelBasedPatchMethod>(points, globalPoint);
0913 }
0914 
0915 QPointF calculateGlobalPos(const std::array<QPointF, 12> &points, const QPointF &localPoint)
0916 {
0917     return calculateGlobalPosImpl<LevelBasedPatchMethod>(points, localPoint);
0918 }
0919 
0920 QPointF calculateLocalPosSVG2(const std::array<QPointF, 12> &points, const QPointF &globalPoint)
0921 {
0922    return calculateLocalPosImpl<SvgPatchMethod>(points, globalPoint);
0923 }
0924 
0925 QPointF calculateGlobalPosSVG2(const std::array<QPointF, 12> &points, const QPointF &localPoint)
0926 {
0927     return calculateGlobalPosImpl<SvgPatchMethod>(points, localPoint);
0928 }
0929 
0930 QPointF interpolateQuadric(const QPointF &p0, const QPointF &p2, const QPointF &pt, qreal t)
0931 {
0932     if (t <= 0.0 || t >= 1.0)
0933         return lerp(p0, p2, 0.5);
0934 
0935     /*
0936         B(t) = [x2 y2] = (1-t)^2*P0 + 2t*(1-t)*P1 + t^2*P2
0937 
0938                B(t) - (1-t)^2*P0 - t^2*P2
0939          P1 =  --------------------------
0940                        2t*(1-t)
0941     */
0942 
0943     QPointF c1 = pt - (1.0-t) * (1.0-t)*p0 - t * t * p2;
0944 
0945     qreal denom = 2.0 * t * (1.0-t);
0946 
0947     c1.rx() /= denom;
0948     c1.ry() /= denom;
0949 
0950     return c1;
0951 }
0952 
0953 std::pair<QPointF, QPointF> offsetSegment(qreal t, const QPointF &offset)
0954 {
0955     /*
0956     * method from inkscape, original method and idea borrowed from Simon Budig
0957     * <simon@gimp.org> and the GIMP
0958     * cf. app/vectors/gimpbezierstroke.c, gimp_bezier_stroke_point_move_relative()
0959     *
0960     * feel good is an arbitrary parameter that distributes the delta between handles
0961     * if t of the drag point is less than 1/6 distance form the endpoint only
0962     * the corresponding handle is adjusted. This matches the behavior in GIMP
0963     */
0964     qreal feel_good;
0965     if (t <= 1.0 / 6.0)
0966         feel_good = 0;
0967     else if (t <= 0.5)
0968         feel_good = (pow((6 * t - 1) / 2.0, 3)) / 2;
0969     else if (t <= 5.0 / 6.0)
0970         feel_good = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
0971     else
0972         feel_good = 1;
0973 
0974     const QPointF moveP1 = ((1-feel_good)/(3*t*(1-t)*(1-t))) * offset;
0975     const QPointF moveP2 = (feel_good/(3*t*t*(1-t))) * offset;
0976 
0977     return std::make_pair(moveP1, moveP2);
0978 }
0979 
0980 qreal curveLength(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, const qreal error)
0981 {
0982     /*
0983      * This algorithm is implemented based on an idea by Jens Gravesen:
0984      * "Adaptive subdivision and the length of Bezier curves" mat-report no. 1992-10, Mathematical Institute,
0985      * The Technical University of Denmark.
0986      *
0987      * By subdividing the curve at parameter value t you only have to find the length of a full Bezier curve.
0988      * If you denote the length of the control polygon by L1 i.e.:
0989      *   L1 = |P0 P1| +|P1 P2| +|P2 P3|
0990      *
0991      * and the length of the cord by L0 i.e.:
0992      *   L0 = |P0 P3|
0993      *
0994      * then
0995      *   L = 1/2*L0 + 1/2*L1
0996      *
0997      * is a good approximation to the length of the curve, and the difference
0998      *   ERR = L1-L0
0999      *
1000      * is a measure of the error. If the error is to large, then you just subdivide curve at parameter value
1001      * 1/2, and find the length of each half.
1002      * If m is the number of subdivisions then the error goes to zero as 2^-4m.
1003      * If you don't have a cubic curve but a curve of degree n then you put
1004      *   L = (2*L0 + (n-1)*L1)/(n+1)
1005      */
1006 
1007     const int deg = bezierDegree(p0, p1, p2, p3);
1008 
1009     if (deg == -1)
1010         return 0.0;
1011 
1012     // calculate chord length
1013     const qreal chordLen = kisDistance(p0, p3);
1014 
1015     if (deg == 1) {
1016         return chordLen;
1017     }
1018 
1019     // calculate length of control polygon
1020     qreal polyLength = 0.0;
1021 
1022     polyLength += kisDistance(p0, p1);
1023     polyLength += kisDistance(p1, p2);
1024     polyLength += kisDistance(p2, p3);
1025 
1026     if ((polyLength - chordLen) > error) {
1027         QPointF q0, q1, q2, q3, q4;
1028         deCasteljau(p0, p1, p2, p3, 0.5, &q0, &q1, &q2, &q3, &q4);
1029 
1030         return curveLength(p0, q0, q1, q2, error) +
1031                 curveLength(q2, q3, q4, p3, error);
1032     } else {
1033         // the error is smaller than our tolerance
1034         if (deg == 3)
1035             return 0.5 * chordLen + 0.5 * polyLength;
1036         else
1037             return (2.0 * chordLen + polyLength) / 3.0;
1038     }
1039 }
1040 
1041 qreal curveLengthAtPoint(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t, const qreal error)
1042 {
1043     QPointF q0, q1, q2, q3, q4;
1044     deCasteljau(p0, p1, p2, p3, t, &q0, &q1, &q2, &q3, &q4);
1045 
1046     return curveLength(p0, q0, q1, q2, error);
1047 }
1048 
1049 qreal curveParamBySegmentLength(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal expectedLength, qreal totalLength, const qreal error)
1050 {
1051     const qreal splitAtParam = expectedLength / totalLength;
1052 
1053     QPointF q0, q1, q2, q3, q4;
1054     deCasteljau(p0, p1, p2, p3, splitAtParam, &q0, &q1, &q2, &q3, &q4);
1055 
1056     const qreal portionLength = curveLength(p0, q0, q1, q2, error);
1057 
1058     if (std::abs(portionLength - expectedLength) < error) {
1059         return splitAtParam;
1060     } else if (portionLength < expectedLength) {
1061         return splitAtParam + (1.0 - splitAtParam) * curveParamBySegmentLength(q2, q3, q4, p3, expectedLength - portionLength, totalLength - portionLength, error);
1062     } else {
1063         return splitAtParam * curveParamBySegmentLength(p0, q0, q1, q2, expectedLength, portionLength, error);
1064     }
1065 }
1066 
1067 
1068 qreal curveParamByProportion(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal proportion, const qreal error)
1069 {
1070     const qreal totalLength = curveLength(p0, p1, p2, p3, error);
1071     const qreal expectedLength = proportion * totalLength;
1072 
1073     return curveParamBySegmentLength(p0, p1, p2, p3, expectedLength, totalLength, error);
1074 }
1075 
1076 qreal curveProportionByParam(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t, const qreal error)
1077 {
1078     return curveLengthAtPoint(p0, p1, p2, p3, t, error) / curveLength(p0, p1, p2, p3, error);
1079 }
1080 
1081 std::pair<QPointF, QPointF> removeBezierNode(const QPointF &p0,
1082                                              const QPointF &p1,
1083                                              const QPointF &p2,
1084                                              const QPointF &p3,
1085                                              const QPointF &q1,
1086                                              const QPointF &q2,
1087                                              const QPointF &q3)
1088 {
1089     /**
1090      * Calculates the curve control point after removal of a node
1091      * by minimizing squared error for the following problem:
1092      *
1093      * Given two consequent 3rd order curves P and Q with lengths Lp and Lq,
1094      * find 3rd order curve B, so that when splitting it at t = Lp / (Lp + Lq)
1095      * (using de Casteljau algorithm) the control points of the resulting
1096      * curves will have least square errors, compared to the corresponding
1097      * control points of curves P and Q.
1098      *
1099      * First we represent curves in matrix form:
1100      *
1101      * B(t) = T * M * B,
1102      * P(t) = T * Z1 * M * P,
1103      * Q(t) = T * Z2 * M * Q,
1104      *
1105      * where
1106      *    T = [1, t, t^2, t^3]
1107      *    M --- 4x4 matrix of Bezier coefficients
1108      *    B, P, Q --- vector of control points for the curves
1109      *
1110      *    Z1 --- conversion matrix that splits the curve into range [0.0...t]
1111      *    Z2 --- conversion matrix that splits the curve into range [t...1.0]
1112      *
1113      * Then we represent vectors P and Q via B:
1114      *
1115      * P = M^(-1) * Z1 * M * B
1116      * Q = M^(-1) * Z2 * M * B
1117      *
1118      * which in block matrix form looks like:
1119      *
1120      * [ P ]   [ M^(-1) * Z1 * M ]
1121      * |   | = |                 | * B
1122      * [ Q ]   [ M^(-1) * Z2 * M ]
1123      *
1124      *
1125      *         [ M^(-1) * Z1 * M ]
1126      * let C = |                 |,
1127      *         [ M^(-1) * Z2 * M ]
1128      *
1129      *     [ P ]
1130      * R = |   |
1131      *     [ Q ]
1132      *
1133      *
1134      * then
1135      *
1136      * R = C * B
1137      *
1138      * applying normal equation to find a solution with least square error,
1139      * get the final result:
1140      *
1141      * B = (C'C)^(-1) * C' * R
1142      */
1143 
1144     const qreal lenP = KisBezierUtils::curveLength(p0, p1, p2, p3, 0.001);
1145     const qreal lenQ = KisBezierUtils::curveLength(p3, q1, q2, q3, 0.001);
1146 
1147     const qreal z = lenP / (lenP + lenQ);
1148 
1149     Eigen::Matrix4f M;
1150     M << 1, 0, 0, 0,
1151          -3, 3, 0, 0,
1152           3, -6, 3, 0,
1153          -1, 3, -3, 1;
1154 
1155     Eigen::DiagonalMatrix<float, 4> Z_1;
1156     Z_1.diagonal() << 1, z, pow2(z), pow3(z);
1157 
1158     Eigen::Matrix4f Z_2;
1159     Z_2 << 1,     z,         pow2(z),               pow3(z),
1160            0, 1 - z, 2 * z * (1 - z), 3 * pow2(z) * (1 - z),
1161            0,     0,     pow2(1 - z),   3 * z * pow2(1 - z),
1162            0,     0,               0,           pow3(1 - z);
1163 
1164     Eigen::Matrix<float, 8, 2> R;
1165     R << p0.x(), p0.y(),
1166          p1.x(), p1.y(),
1167          p2.x(), p2.y(),
1168          p3.x(), p3.y(),
1169          p3.x(), p3.y(),
1170          q1.x(), q1.y(),
1171          q2.x(), q2.y(),
1172          q3.x(), q3.y();
1173 
1174     Eigen::Matrix<float, 2, 2> B_const;
1175     B_const << p0.x(), p0.y(),
1176                q3.x(), q3.y();
1177 
1178 
1179     Eigen::Matrix4f M1 = M.inverse() * Z_1 * M;
1180     Eigen::Matrix4f M2 = M.inverse() * Z_2 * M;
1181 
1182     Eigen::Matrix<float, 8, 4> C;
1183     C << M1, M2;
1184 
1185     Eigen::Matrix<float, 8, 2> C_const;
1186     C_const << C.col(0), C.col(3);
1187 
1188     Eigen::Matrix<float, 8, 2> C_var;
1189     C_var << C.col(1), C.col(2);
1190 
1191     Eigen::Matrix<float, 8, 2> R_var;
1192     R_var = R - C_const * B_const;
1193 
1194     Eigen::Matrix<float, 6, 2> R_reduced;
1195     R_reduced = R_var.block(1, 0, 6, 2);
1196 
1197     Eigen::Matrix<float, 6, 2> C_reduced;
1198     C_reduced = C_var.block(1, 0, 6, 2);
1199 
1200     Eigen::Matrix<float, 2, 2> result;
1201     result = (C_reduced.transpose() * C_reduced).inverse() * C_reduced.transpose() * R_reduced;
1202 
1203     QPointF resultP0(result(0, 0), result(0, 1));
1204     QPointF resultP1(result(1, 0), result(1, 1));
1205 
1206     return std::make_pair(resultP0, resultP1);
1207 }
1208 QVector<qreal> intersectWithLineImpl(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, qreal eps, qreal alpha, qreal beta)
1209 {
1210     using KisAlgebra2D::intersectLines;
1211 
1212     QVector<qreal> result;
1213 
1214     const qreal length =
1215             kisDistance(p0, p1) +
1216             kisDistance(p1, p2) +
1217             kisDistance(p2, p3);
1218 
1219     if (length < eps) {
1220         if (intersectLines(p0, p3, line.p1(), line.p2())) {
1221             result << alpha * 0.5 + beta;
1222         }
1223     } else {
1224 
1225         const bool hasIntersections =
1226                 intersectLines(p0, p1, line.p1(), line.p2()) ||
1227                 intersectLines(p1, p2, line.p1(), line.p2()) ||
1228                 intersectLines(p2, p3, line.p1(), line.p2());
1229 
1230         if (hasIntersections) {
1231             QPointF q0, q1, q2, q3, q4;
1232 
1233             deCasteljau(p0, p1, p2, p3, 0.5, &q0, &q1, &q2, &q3, &q4);
1234 
1235             result << intersectWithLineImpl(p0, q0, q1, q2, line, eps, 0.5 * alpha, beta);
1236             result << intersectWithLineImpl(q2, q3, q4, p3, line, eps, 0.5 * alpha, beta + 0.5 * alpha);
1237         }
1238     }
1239     return result;
1240 }
1241 
1242 QVector<qreal> intersectWithLine(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, qreal eps)
1243 {
1244     return intersectWithLineImpl(p0, p1, p2, p3, line, eps, 1.0, 0.0);
1245 }
1246 
1247 boost::optional<qreal> intersectWithLineNearest(const QPointF &p0, const QPointF &p1, const QPointF &p2, const QPointF &p3, const QLineF &line, const QPointF &nearestAnchor, qreal eps)
1248 {
1249     QVector<qreal> result = intersectWithLine(p0, p1, p2, p3, line, eps);
1250 
1251     qreal minDistance = std::numeric_limits<qreal>::max();
1252     boost::optional<qreal> nearestRoot;
1253 
1254     Q_FOREACH (qreal root, result) {
1255         const QPointF pt = bezierCurve(p0, p1, p2, p3, root);
1256         const qreal distance = kisDistance(pt, nearestAnchor);
1257 
1258         if (distance < minDistance) {
1259             minDistance = distance;
1260             nearestRoot = root;
1261         }
1262     }
1263 
1264     return nearestRoot;
1265 }
1266 
1267 }