1 /*
2  *  tool_transform_args.h - part of Krita
3  *
4  *  Copyright (c) 2010 Marc Pegon <pe.marc@free.fr>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #ifndef TOOL_TRANSFORM_ARGS_H_
22 #define TOOL_TRANSFORM_ARGS_H_
23 
24 #include <QPointF>
25 #include <QVector3D>
26 #include <kis_warptransform_worker.h>
27 #include <kis_filter_strategy.h>
28 #include "kis_liquify_properties.h"
29 #include "kritatooltransform_export.h"
30 #include "kis_global.h"
31 #include "KisToolChangesTrackerData.h"
32 #include "KisBezierTransformMesh.h"
33 
34 #include <QScopedPointer>
35 class KisLiquifyTransformWorker;
36 class QDomElement;
37 
38 /**
39  * Class used to store the parameters of a transformation.
40  * Some parameters are specific to free transform mode, and
41  * others to warp mode : maybe add a union to save a little more
42  * memory.
43  */
44 
45 class KRITATOOLTRANSFORM_EXPORT ToolTransformArgs : public KisToolChangesTrackerData
46 {
47 public:
48     enum TransformMode {FREE_TRANSFORM = 0,
49                         WARP,
50                         CAGE,
51                         LIQUIFY,
52                         PERSPECTIVE_4POINT,
53                         MESH,
54                         N_MODES};
55 
56     /**
57      * Initializes the parameters for an identity transformation,
58      * with mode set to free transform.
59      */
60     ToolTransformArgs();
61 
62     /**
63      * The object return will be a copy of args.
64      */
65     ToolTransformArgs(const ToolTransformArgs& args);
66 
67     KisToolChangesTrackerData *clone() const;
68 
69     /**
70      * If mode is warp, original and transformed vector points will be of size 0.
71      * Use setPoints method to set those vectors.
72      */
73     ToolTransformArgs(TransformMode mode,
74                       QPointF transformedCenter,
75                       QPointF originalCenter,
76                       QPointF rotationCenterOffset, bool transformAroundRotationCenter,
77                       double aX, double aY, double aZ,
78                       double scaleX, double scaleY,
79                       double shearX, double shearY,
80                       KisWarpTransformWorker::WarpType warpType,
81                       double alpha,
82                       bool defaultPoints,
83                       const QString &filterId,
84                       int pixelPrecision, int previewPixelPrecision);
85     ~ToolTransformArgs();
86     ToolTransformArgs& operator=(const ToolTransformArgs& args);
87 
88     bool operator==(const ToolTransformArgs& other) const;
89     bool isSameMode(const ToolTransformArgs& other) const;
90 
mode()91     inline TransformMode mode() const {
92         return m_mode;
93     }
setMode(TransformMode mode)94     inline void setMode(TransformMode mode) {
95         m_mode = mode;
96     }
97 
pixelPrecision()98     inline int pixelPrecision() const {
99         return m_pixelPrecision;
100     }
101 
setPixelPrecision(int precision)102     inline void setPixelPrecision(int precision) {
103         m_pixelPrecision = precision;
104     }
105 
previewPixelPrecision()106     inline int previewPixelPrecision() const {
107         return m_previewPixelPrecision;
108     }
109 
setPreviewPixelPrecision(int precision)110     inline void setPreviewPixelPrecision(int precision) {
111         m_previewPixelPrecision = precision;
112     }
113 
114     //warp-related
numPoints()115     inline int numPoints() const {
116         KIS_ASSERT_RECOVER_NOOP(m_origPoints.size() == m_transfPoints.size());
117         return m_origPoints.size();
118     }
origPoint(int i)119     inline QPointF &origPoint(int i) {
120         return m_origPoints[i];
121     }
transfPoint(int i)122     inline QPointF &transfPoint(int i) {
123         return m_transfPoints[i];
124     }
origPoints()125     inline const QVector<QPointF> &origPoints() const {
126         return m_origPoints;
127     }
transfPoints()128     inline const QVector<QPointF> &transfPoints() const {
129         return m_transfPoints;
130     }
131 
refOriginalPoints()132     inline QVector<QPointF> &refOriginalPoints() {
133         return m_origPoints;
134     }
refTransformedPoints()135     inline QVector<QPointF> &refTransformedPoints() {
136         return m_transfPoints;
137     }
138 
warpType()139     inline KisWarpTransformWorker::WarpType warpType() const {
140         return m_warpType;
141     }
alpha()142     inline double alpha() const {
143         return m_alpha;
144     }
defaultPoints()145     inline bool defaultPoints() const {
146         return m_defaultPoints;
147     }
setPoints(QVector<QPointF> origPoints,QVector<QPointF> transfPoints)148     inline void setPoints(QVector<QPointF> origPoints, QVector<QPointF> transfPoints) {
149         m_origPoints = QVector<QPointF>(origPoints);
150         m_transfPoints = QVector<QPointF>(transfPoints);
151     }
setWarpType(KisWarpTransformWorker::WarpType warpType)152     inline void setWarpType(KisWarpTransformWorker::WarpType warpType) {
153         m_warpType = warpType;
154     }
setWarpCalculation(KisWarpTransformWorker::WarpCalculation warpCalc)155     inline void setWarpCalculation(KisWarpTransformWorker::WarpCalculation warpCalc) {
156         m_warpCalculation = warpCalc;
157     }
warpCalculation()158     inline KisWarpTransformWorker::WarpCalculation warpCalculation() {
159         return m_warpCalculation;
160     }
161 
setAlpha(double alpha)162     inline void setAlpha(double alpha) {
163         m_alpha = alpha;
164     }
setDefaultPoints(bool defaultPoints)165     inline void setDefaultPoints(bool defaultPoints) {
166         m_defaultPoints = defaultPoints;
167     }
168 
169     //"free transform"-related
transformedCenter()170     inline QPointF transformedCenter() const {
171         return m_transformedCenter;
172     }
originalCenter()173     inline QPointF originalCenter() const {
174         return m_originalCenter;
175     }
rotationCenterOffset()176     inline QPointF rotationCenterOffset() const {
177         return m_rotationCenterOffset;
178     }
transformAroundRotationCenter()179     inline bool transformAroundRotationCenter() const {
180         return m_transformAroundRotationCenter;
181     }
aX()182     inline double aX() const {
183         return m_aX;
184     }
aY()185     inline double aY() const {
186         return m_aY;
187     }
aZ()188     inline double aZ() const {
189         return m_aZ;
190     }
cameraPos()191     inline QVector3D cameraPos() const {
192         return m_cameraPos;
193     }
scaleX()194     inline double scaleX() const {
195         return m_scaleX;
196     }
scaleY()197     inline double scaleY() const {
198         return m_scaleY;
199     }
keepAspectRatio()200     inline bool keepAspectRatio() const {
201         return m_keepAspectRatio;
202     }
shearX()203     inline double shearX() const {
204         return m_shearX;
205     }
shearY()206     inline double shearY() const {
207         return m_shearY;
208     }
209 
setTransformedCenter(QPointF transformedCenter)210     inline void setTransformedCenter(QPointF transformedCenter) {
211         m_transformedCenter = transformedCenter;
212     }
setOriginalCenter(QPointF originalCenter)213     inline void setOriginalCenter(QPointF originalCenter) {
214         m_originalCenter = originalCenter;
215     }
setRotationCenterOffset(QPointF rotationCenterOffset)216     inline void setRotationCenterOffset(QPointF rotationCenterOffset) {
217         m_rotationCenterOffset = rotationCenterOffset;
218     }
219     void setTransformAroundRotationCenter(bool value);
220 
setAX(double aX)221     inline void setAX(double aX) {
222         KIS_SAFE_ASSERT_RECOVER(qFuzzyCompare(aX, normalizeAngle(aX))) {
223             aX = normalizeAngle(aX);
224         }
225 
226         m_aX = aX;
227     }
setAY(double aY)228     inline void setAY(double aY) {
229         KIS_SAFE_ASSERT_RECOVER(qFuzzyCompare(aY, normalizeAngle(aY))) {
230             aY = normalizeAngle(aY);
231         }
232 
233         m_aY = aY;
234     }
setAZ(double aZ)235     inline void setAZ(double aZ) {
236         KIS_SAFE_ASSERT_RECOVER(qFuzzyCompare(aZ, normalizeAngle(aZ))) {
237             aZ = normalizeAngle(aZ);
238         }
239 
240         m_aZ = aZ;
241     }
setCameraPos(const QVector3D & pos)242     inline void setCameraPos(const QVector3D &pos) {
243         m_cameraPos = pos;
244     }
setScaleX(double scaleX)245     inline void setScaleX(double scaleX) {
246         m_scaleX = scaleX;
247     }
setScaleY(double scaleY)248     inline void setScaleY(double scaleY) {
249         m_scaleY = scaleY;
250     }
setKeepAspectRatio(bool value)251     inline void setKeepAspectRatio(bool value) {
252         m_keepAspectRatio = value;
253     }
setShearX(double shearX)254     inline void setShearX(double shearX) {
255         m_shearX = shearX;
256     }
setShearY(double shearY)257     inline void setShearY(double shearY) {
258         m_shearY = shearY;
259     }
260 
filterId()261     inline QString filterId() const {
262         return m_filter->id();
263     }
264 
265     void setFilterId(const QString &id);
266 
filter()267     inline KisFilterStrategy* filter() const {
268         return m_filter;
269     }
270 
271     bool isIdentity() const;
272 
flattenedPerspectiveTransform()273     inline QTransform flattenedPerspectiveTransform() const {
274         return m_flattenedPerspectiveTransform;
275     }
276 
setFlattenedPerspectiveTransform(const QTransform & value)277     inline void setFlattenedPerspectiveTransform(const QTransform &value) {
278         m_flattenedPerspectiveTransform = value;
279     }
280 
isEditingTransformPoints()281     bool isEditingTransformPoints() const {
282         return m_editTransformPoints;
283     }
284 
setEditingTransformPoints(bool value)285     void setEditingTransformPoints(bool value) {
286         m_editTransformPoints = value;
287     }
288 
liquifyProperties()289     const KisLiquifyProperties* liquifyProperties() const {
290         return m_liquifyProperties.data();
291     }
292 
liquifyProperties()293     KisLiquifyProperties* liquifyProperties() {
294         return m_liquifyProperties.data();
295     }
296 
297     void initLiquifyTransformMode(const QRect &srcRect);
298     void saveLiquifyTransformMode() const;
299 
liquifyWorker()300     KisLiquifyTransformWorker* liquifyWorker() const {
301         return m_liquifyWorker.data();
302     }
303 
304     void toXML(QDomElement *e) const;
305     static ToolTransformArgs fromXML(const QDomElement &e);
306 
307     void translate(const QPointF &offset);
308 
309     void saveContinuedState();
310     void restoreContinuedState();
311     const ToolTransformArgs* continuedTransform() const;
312 
313     const KisBezierTransformMesh* meshTransform() const;
314     KisBezierTransformMesh* meshTransform();
315 
316     bool meshShowHandles() const;
317     void setMeshShowHandles(bool value);
318 
319     bool meshSymmetricalHandles() const;
320     void setMeshSymmetricalHandles(bool meshSymmetricalHandles);
321 
322     bool meshScaleHandles() const;
323     void setMeshScaleHandles(bool meshScaleHandles);
324 
325 private:
326     void clear();
327     void init(const ToolTransformArgs& args);
328     TransformMode m_mode {ToolTransformArgs::TransformMode::FREE_TRANSFORM};
329 
330     // warp-related arguments
331     // these are basically the arguments taken by the warp transform worker
332     bool m_defaultPoints {true}; // true : the original points are set to make a grid
333                           // which density is given by numPoints()
334     QVector<QPointF> m_origPoints;
335     QVector<QPointF> m_transfPoints;
336     KisWarpTransformWorker::WarpType m_warpType {KisWarpTransformWorker::WarpType_::RIGID_TRANSFORM};
337     KisWarpTransformWorker::WarpCalculation m_warpCalculation {KisWarpTransformWorker::WarpCalculation::DRAW}; // DRAW or GRID
338     double m_alpha {1.0};
339 
340     //'free transform'-related
341     // basically the arguments taken by the transform worker
342     QPointF m_transformedCenter;
343     QPointF m_originalCenter;
344     QPointF m_rotationCenterOffset; // the position of the rotation center relative to
345                                     // the original top left corner of the selection
346                                     // before any transformation
347     bool m_transformAroundRotationCenter {false}; // In freehand mode makes the scaling and other transformations
348                                           // be anchored to the rotation center point.
349 
350     double m_aX {0};
351     double m_aY {0};
352     double m_aZ {0};
353     QVector3D m_cameraPos {QVector3D(0,0,1024)};
354     double m_scaleX {1.0};
355     double m_scaleY {1.0};
356     double m_shearX {0.0};
357     double m_shearY {0.0};
358     bool m_keepAspectRatio {false};
359 
360     // perspective trasform related
361     QTransform m_flattenedPerspectiveTransform;
362 
363     KisFilterStrategy *m_filter {0};
364     bool m_editTransformPoints {false};
365     QSharedPointer<KisLiquifyProperties> m_liquifyProperties;
366     QScopedPointer<KisLiquifyTransformWorker> m_liquifyWorker;
367 
368     KisBezierTransformMesh m_meshTransform;
369     bool m_meshShowHandles = true;
370     bool m_meshSymmetricalHandles = true;
371     bool m_meshScaleHandles = false;
372 
373     /**
374      * When we continue a transformation, m_continuedTransformation
375      * stores the initial step of our transform. All cancel and revert
376      * operations should revert to it.
377      */
378     QScopedPointer<ToolTransformArgs> m_continuedTransformation;
379 
380     //PixelPrecision should always be in powers of 2
381     int m_pixelPrecision {8};
382     int m_previewPixelPrecision {16};
383 };
384 
385 #endif // TOOL_TRANSFORM_ARGS_H_
386