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_