File indexing completed on 2024-06-23 04:27:08

0001 /*
0002  * KDE. Krita Project.
0003  *
0004  * SPDX-FileCopyrightText: 2021 Deif Lou <ginoba@gmail.com>
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #ifndef KISSCREENTONEGENERATORTEMPLATESAMPLER_H
0010 #define KISSCREENTONEGENERATORTEMPLATESAMPLER_H
0011 
0012 #include <QtGlobal>
0013 #include <QVector>
0014 #include <QTransform>
0015 
0016 #include <cmath>
0017 
0018 template <typename Template>
0019 class KisScreentoneGeneratorAlignedTemplateSampler
0020 {
0021 public:
0022     KisScreentoneGeneratorAlignedTemplateSampler(const Template &the_template)
0023         : m_template(the_template)
0024     {}
0025 
0026     qreal operator()(qreal x, qreal y) const
0027     {
0028         // Get the coordinates in template space
0029         QPointF p(
0030             x + std::round(m_template.screenPosition().x()),
0031             y + std::round(m_template.screenPosition().y())
0032         );
0033         // Get the coordinates in screen space
0034         const QPointF screenPos = m_template.templateToScreenTransform().map(p);
0035         // Get x/y indices in macrocell units or the current macrocell tile
0036         // position
0037         const qreal a = -std::floor(screenPos.x() / static_cast<qreal>(m_template.macrocellSize().width()));
0038         const qreal b = -std::floor(screenPos.y() / static_cast<qreal>(m_template.macrocellSize().height()));
0039         // Get the correspondent point in the (0, 0) macrocell tile
0040         p += QPointF(a * m_template.v1().x() + b * m_template.v2().x(), a * m_template.v1().y() + b * m_template.v2().y());
0041 
0042         const int i = static_cast<int>(std::floor(p.x())) + m_template.originOffset().x();
0043         const int j = static_cast<int>(std::floor(p.y())) + m_template.originOffset().y();
0044         const int macrocellPointIndex = j * m_template.templateSize().width() + i;
0045         return m_template.templateData()[macrocellPointIndex];
0046     }
0047 
0048 private:
0049     const Template& m_template;
0050 };
0051 
0052 template <typename Template>
0053 class KisScreentoneGeneratorUnAlignedTemplateSampler
0054 {
0055 public:
0056     KisScreentoneGeneratorUnAlignedTemplateSampler(const Template &the_template)
0057         : m_template(the_template)
0058     {}
0059 
0060     qreal operator()(qreal x, qreal y) const
0061     {
0062         // Get the coordinates in screen space
0063         qreal xx, yy;
0064         m_template.imageToScreenTransform().map(x, y, &xx, &yy);
0065         // Convert to coordinate inside the macrocell
0066         xx -= std::floor(xx / m_template.macrocellSize().width()) * m_template.macrocellSize().width();
0067         yy -= std::floor(yy / m_template.macrocellSize().height()) * m_template.macrocellSize().height();
0068         // Get template coordinates
0069         QPointF templatePoint = m_template.screenToTemplateTransform().map(QPointF(xx, yy)) +
0070                                 m_template.originOffset();
0071         
0072         // Bilinear interpolation
0073         // Get integer coordinates of the template points to use in the interpolation
0074         const int ix0 =
0075             templatePoint.x() < 0.0 ? m_template.templateSize().width() - 1 :
0076                 (templatePoint.x() >= m_template.templateSize().width() ? 0.0 :
0077                     static_cast<int>(std::floor(templatePoint.x())));
0078         const int iy0 =
0079             templatePoint.y() < 0.0 ? m_template.templateSize().height() - 1 :
0080                 (templatePoint.y() >= m_template.templateSize().height() ? 0.0 :
0081                     static_cast<int>(std::floor(templatePoint.y())));
0082         const int ix1 = ix0 == m_template.templateSize().width() - 1 ? 0 : ix0 + 1;
0083         const int iy1 = iy0 == m_template.templateSize().height() - 1 ? 0 : iy0 + 1;
0084         // Get the template values for the points
0085         const qreal topLeftValue = m_template.templateData()[iy0 * m_template.templateSize().width() + ix0];
0086         const qreal topRightValue = m_template.templateData()[iy0 * m_template.templateSize().width() + ix1];
0087         const qreal bottomLeftValue = m_template.templateData()[iy1 * m_template.templateSize().width() + ix0];
0088         const qreal bottomRightValue = m_template.templateData()[iy1 * m_template.templateSize().width() + ix1];
0089         // Get the fractional part of the point to use in the interpolation
0090         const qreal fractionalX = templatePoint.x() - std::floor(templatePoint.x());
0091         const qreal fractionalY = templatePoint.y() - std::floor(templatePoint.y());
0092         // Perform bilinear interpolation
0093         const qreal a = topLeftValue * (1.0 - fractionalX) + topRightValue * fractionalX;
0094         const qreal b = bottomLeftValue * (1.0 - fractionalX) + bottomRightValue * fractionalX;
0095         const qreal c = a * (1.0 - fractionalY) + b * fractionalY;
0096         // ----
0097         return c;
0098     }
0099 
0100 private:
0101     const Template& m_template;
0102 };
0103 
0104 #endif