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

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 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 private:
0110     // XXX (BSAR): Why didn't we use the shared-pointer versions of the paint device classes?
0111     // CBR: because the template functions used within don't work if it's not true pointers
0112     template <class T> void transformPass(KisPaintDevice* src,
0113                                           KisPaintDevice* dst,
0114                                           double xscale,
0115                                           double  shear,
0116                                           double dx,
0117                                           KisFilterStrategy *filterStrategy,
0118                                           int portion);
0119 
0120     friend class KisTransformWorkerTest;
0121 
0122     static QRect rotateRight90(KisPaintDeviceSP dev,
0123                                QRect boundRect,
0124                                KoUpdaterPtr progressUpdater,
0125                                int portion);
0126 
0127     static QRect rotateLeft90(KisPaintDeviceSP dev,
0128                               QRect boundRect,
0129                               KoUpdaterPtr progressUpdater,
0130                               int portion);
0131 
0132     static QRect rotate180(KisPaintDeviceSP dev,
0133                            QRect boundRect,
0134                            KoUpdaterPtr progressUpdater,
0135                            int portion);
0136 
0137 private:
0138     KisPaintDeviceSP m_dev;
0139     double  m_xscale, m_yscale;
0140     double  m_xshear, m_yshear, m_rotation;
0141     double  m_xshearOrigin, m_yshearOrigin;
0142     qreal  m_xtranslate, m_ytranslate;
0143     KoUpdaterPtr m_progressUpdater;
0144     KisFilterStrategy *m_filter;
0145     QRect m_boundRect;
0146 };
0147 
0148 #endif // KIS_TRANSFORM_VISITOR_H_