File indexing completed on 2024-05-19 04:26:38

0001 /*
0002  *  SPDX-FileCopyrightText: 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
0003  *  SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
0004  *  SPDX-FileCopyrightText: 2010 Marc Pegon <pe.marc@free.fr>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #ifndef KIS_TRANSFORM_WORKER_H_
0010 #define KIS_TRANSFORM_WORKER_H_
0011 
0012 #include "kis_types.h"
0013 #include "kritaimage_export.h"
0014 
0015 #include <QRect>
0016 #include <KoUpdater.h>
0017 
0018 class KisPaintDevice;
0019 class KisFilterStrategy;
0020 class QTransform;
0021 
0022 class KRITAIMAGE_EXPORT KisTransformWorker
0023 {
0024 
0025 /* What are xshearOrigin, yshearOrigin :
0026  *
0027  * let's keep it simple and say we only have horizontal shearing (it's similar with vertical shearing)
0028  * that means we will apply the transformation :
0029  * x' = x + xshear * y and y' = y, where x,y are the old coordinates of the pixels, and x' y' the new coordinates
0030  * that means, the more we go down in the image (y++), the more x' is different from x
0031  * most of the times, we want to shear a part of the image centered at y = y0 != 0.
0032  * i.e. we want x' = x at y = y0
0033  * in that case, it's good to apply instead x' = x + xshear * (y - yshearOrigin), y' = y.
0034  * please note that it's still possible to obtain the same result by copying the part you want to shear at
0035  * in another paintDevice at y = -y0 and use the transformWorker with yshearOrigin = 0.
0036 */
0037 public:
0038     KisTransformWorker(KisPaintDeviceSP dev,
0039                        double  xscale, double  yscale,
0040                        double  xshear, double  yshear,
0041                        double  xshearOrigin, double yshearOrigin,
0042                        double rotation,
0043                        qreal xtranslate, qreal ytranslate,
0044                        KoUpdaterPtr progress,
0045                        KisFilterStrategy *filter);
0046     ~KisTransformWorker();
0047 
0048 
0049     /**
0050      * Mirror the specified device along the X or Y axis at the
0051      * coordinate \p axis.
0052      */
0053     static void mirror(KisPaintDeviceSP dev, qreal axis, Qt::Orientation orientation);
0054 
0055     /**
0056      * Convenience methods for mirror(dev, axis, orientation)
0057      */
0058     static void mirrorX(KisPaintDeviceSP dev, qreal axis);
0059     static void mirrorY(KisPaintDeviceSP dev, qreal axis);
0060 
0061     /**
0062      * Mirror the device relative to the center of its exactBounds()
0063      */
0064     static void mirrorX(KisPaintDeviceSP dev);
0065     static void mirrorY(KisPaintDeviceSP dev);
0066 
0067     /**
0068      * Offset the specified device with wrapping around edges of rect specified as QRect(0,0,wrapSize.width, wrapSize.height)*
0069      * @param device device to be offset
0070      * @param offsetPosition position where the new origin will be
0071      * @param wrapRect width and height of the wrap edge, usual scenario is to use canvas width&height
0072      *
0073      **/
0074     static void offset(KisPaintDeviceSP device, const QPoint &offsetPosition, const QRect &wrapRect);
0075 
0076 
0077 public:
0078 
0079     // returns false if interrupted
0080     bool run();
0081     bool runPartial(const QRect &processRect);
0082 
0083     /**
0084      * Returns a matrix of the transformation executed by the worker.
0085      * Resulting transformation has the following form (in Qt's matrix
0086      * notation (all the matrices are transposed)):
0087      *
0088      * transform = TS.inverted() * S * TS * SC * R * T
0089      *
0090      * ,where:
0091      * TS - shear origin transpose
0092      * S  - shear itself (shearX * shearY)
0093      * SC - scale
0094      * R  - rotation (@p rotation parameter)
0095      * T  - transpose (@p xtranslate, @p ytranslate)
0096      *
0097      * WARNING: due to some rounding problems in the worker
0098      * the work it does not correspond to the matrix exactly!
0099      * The result always differs 1-3 pixel. So be careful with it
0100      * (or fix it)
0101      */
0102     QTransform transform() const;
0103 
0104     /**
0105      * Transforms the outline of the pixel selection (if it is valid)
0106      */
0107     void transformPixelSelectionOutline(KisPixelSelectionSP pixelSelection) const;
0108 
0109     bool forceSubPixelTranslation() const;
0110     void setForceSubPixelTranslation(bool value);
0111 
0112 private:
0113     // XXX (BSAR): Why didn't we use the shared-pointer versions of the paint device classes?
0114     // CBR: because the template functions used within don't work if it's not true pointers
0115     template <class T> void transformPass(KisPaintDevice* src,
0116                                           KisPaintDevice* dst,
0117                                           double xscale,
0118                                           double  shear,
0119                                           double dx,
0120                                           KisFilterStrategy *filterStrategy,
0121                                           int portion);
0122 
0123     friend class KisTransformWorkerTest;
0124 
0125     static QRect rotateRight90(KisPaintDeviceSP dev,
0126                                QRect boundRect,
0127                                KoUpdaterPtr progressUpdater,
0128                                int portion);
0129 
0130     static QRect rotateLeft90(KisPaintDeviceSP dev,
0131                               QRect boundRect,
0132                               KoUpdaterPtr progressUpdater,
0133                               int portion);
0134 
0135     static QRect rotate180(KisPaintDeviceSP dev,
0136                            QRect boundRect,
0137                            KoUpdaterPtr progressUpdater,
0138                            int portion);
0139 
0140 private:
0141     KisPaintDeviceSP m_dev;
0142     double  m_xscale, m_yscale;
0143     double  m_xshear, m_yshear, m_rotation;
0144     double  m_xshearOrigin, m_yshearOrigin;
0145     qreal  m_xtranslate, m_ytranslate;
0146     KoUpdaterPtr m_progressUpdater;
0147     KisFilterStrategy *m_filter;
0148     QRect m_boundRect;
0149     bool m_forceSubPixelTranslation {false};
0150 };
0151 
0152 #endif // KIS_TRANSFORM_VISITOR_H_