File indexing completed on 2024-05-12 15:58:16

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_FOUR_POINT_INTERPOLATOR_BACKWARD_H
0008 #define __KIS_FOUR_POINT_INTERPOLATOR_BACKWARD_H
0009 
0010 #include <QPolygon>
0011 #include <QPointF>
0012 
0013 #include "kis_global.h"
0014 #include "kis_algebra_2d.h"
0015 
0016 
0017 /**
0018  *    A-----B         The polygons must be initialized in this order:
0019  *    |     |
0020  *    |     |         polygon << A << B << D << C;
0021  *    C-----D
0022  */
0023 
0024 class KisFourPointInterpolatorBackward
0025 {
0026 public:
0027     KisFourPointInterpolatorBackward(const QPolygonF &srcPolygon, const QPolygonF &dstPolygon) {
0028         m_a = dstPolygon[1] - dstPolygon[0]; // AB
0029         m_b = dstPolygon[2] - dstPolygon[1]; // BD
0030         m_c = dstPolygon[3] - dstPolygon[0]; // AC
0031         m_d = m_b - m_c; // BD - AC
0032 
0033         m_qA = m_c.x() * m_d.y() - m_c.y() * m_d.x();
0034 
0035         m_srcBase = srcPolygon[0];
0036         m_dstBase = dstPolygon[0];
0037         m_xCoeff = srcPolygon[1].x() - srcPolygon[0].x(); // AB_src
0038         m_yCoeff = srcPolygon[3].y() - srcPolygon[0].y(); // AC_src
0039 
0040         m_qB_const = m_c.x() * m_a.y() - m_c.y() * m_a.x();
0041 
0042         m_qD_div = 1.0 / (2 * m_qA);
0043 
0044         //m_qB_varX = 0.0;
0045         //m_qB_varY = 0.0;
0046     }
0047 
0048     /**
0049      * Checks if linear dimensions of the destination polygon are
0050      * bigger than \p tolerance.
0051      */
0052     inline bool isValid(const qreal tolerance = 0.1) const {
0053         const qreal toleranceSq = pow2(tolerance);
0054 
0055         const qreal sq1 = qAbs(m_qB_const);
0056         const qreal sq2 = qAbs(KisAlgebra2D::crossProduct(m_b, m_c - m_b + m_a));
0057 
0058         return sq1 + sq2 > 2 * toleranceSq;
0059     }
0060 
0061     inline QPointF fallbackSourcePoint() const {
0062         return m_srcBase + QPointF(0.5 * m_xCoeff, 0.5 * m_yCoeff);
0063     }
0064 
0065     inline QPointF map(const QPointF &pt) {
0066         setX(pt.x());
0067         setY(pt.y());
0068         return getValue();
0069     }
0070 
0071     inline void setX(qreal x) {
0072         x -= m_dstBase.x();
0073 
0074         m_qB_varX = - x * m_d.y();
0075         m_qC_varX = - x * m_a.y();
0076         m_px = x;
0077     }
0078 
0079     inline void setY(qreal y) {
0080         y -= m_dstBase.y();
0081 
0082         m_qB_varY = y * m_d.x();
0083         m_qC_varY = y * m_a.x();
0084         m_py = y;
0085     }
0086 
0087     inline QPointF getValue() const {
0088         static const qreal eps = 1e-10;
0089 
0090         qreal qB = m_qB_const + m_qB_varX + m_qB_varY;
0091         qreal qC = m_qC_varX + m_qC_varY;
0092 
0093         qreal nu = 0.0;
0094 
0095         if (qAbs(m_qA) < eps) {
0096             nu = -qC / qB;
0097         } else {
0098             qreal D = pow2(qB) - 4 * m_qA * qC;
0099             if (D > 0.0) {
0100                 qreal sqrtD = std::sqrt(D);
0101                 nu = (-qB - sqrtD) * m_qD_div;
0102                 if (nu < 0.0 || nu > 1.0) {
0103                     qreal nu2 = (-qB + sqrtD) * m_qD_div;
0104 
0105                     if (nu2 < 0.0 || nu2 > 1.0) {
0106                         nu = qBound(qreal(0.0), nu, qreal(1.0));
0107                     } else {
0108                         nu = nu2;
0109                     }
0110                 }
0111             } else {
0112                 nu = 0.0;
0113             }
0114         }
0115 
0116         qreal xBasedDenominator = m_a.x() + nu * m_d.x();
0117 
0118         qreal mu;
0119 
0120         if (qAbs(xBasedDenominator) > eps) {
0121             mu = (m_px - nu * m_c.x()) / xBasedDenominator;
0122         } else {
0123             mu = (m_py - nu * m_c.y()) / (m_a.y() + nu * m_d.y());
0124         }
0125 
0126         return m_srcBase + QPointF(mu * m_xCoeff, nu * m_yCoeff);
0127     }
0128 
0129 private:
0130     QPointF m_a; // AB
0131     QPointF m_b; // BD
0132     QPointF m_c; // AC
0133     QPointF m_d; // m_b - m_c
0134 
0135     qreal m_qA {0.0}; // quadratic equation A coeff
0136     qreal m_qB_const {0.0}; // quadratic equation B coeff, const part
0137     qreal m_qB_varX {0.0}; // quadratic equation B coeff, X-dep part
0138     qreal m_qB_varY {0.0}; // quadratic equation B coeff, Y-dep part
0139     qreal m_qC_varX {0.0}; // quadratic equation C coeff, X-dep part
0140     qreal m_qC_varY {0.0}; // quadratic equation C coeff, Y-dep part
0141     qreal m_qD_div {0.0}; // inverted divisor of the quadratic equation solution
0142     qreal m_px {0.0}; // saved relative X coordinate
0143     qreal m_py {0.0}; // saved relative Y coordinate
0144 
0145     QPointF m_srcBase;
0146     QPointF m_dstBase;
0147     qreal m_xCoeff {0.0};
0148     qreal m_yCoeff {0.0};
0149 };
0150 
0151 #endif /* __KIS_FOUR_POINT_INTERPOLATOR_BACKWARD_H */