Krita Source Code Documentation
Loading...
Searching...
No Matches
tool_transform_args.cc
Go to the documentation of this file.
1/*
2 * tool_transform_args.h - part of Krita
3 *
4 * SPDX-FileCopyrightText: 2010 Marc Pegon <pe.marc@free.fr>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
10
11#include <QDomElement>
12
13#include <ksharedconfig.h>
14#include <kconfig.h>
15#include <kconfiggroup.h>
16
18#include "kis_dom_utils.h"
19#include <QMatrix4x4>
20
21
23 : m_liquifyProperties(new KisLiquifyProperties())
24{
25 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
26 QString savedFilterId = configGroup.readEntry("filterId", "Bicubic");
27 setFilterId(savedFilterId);
28 m_transformAroundRotationCenter = configGroup.readEntry("transformAroundRotationCenter", "0").toInt();
29 m_meshShowHandles = configGroup.readEntry("meshShowHandles", true);
30 m_meshSymmetricalHandles = configGroup.readEntry("meshSymmetricalHandles", true);
31 m_meshScaleHandles = configGroup.readEntry("meshScaleHandles", false);
32}
33
34void ToolTransformArgs::setFilterId(const QString &id) {
36
37 if (m_filter) {
38 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
39 configGroup.writeEntry("filterId", id);
40 }
41}
42
44{
46
47 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
48 configGroup.writeEntry("transformAroundRotationCenter", int(value));
49}
50
52{
53 m_mode = args.mode();
59 m_aX = args.aX();
60 m_aY = args.aY();
61 m_aZ = args.aZ();
62 m_scaleX = args.scaleX();
63 m_scaleY = args.scaleY();
64 m_shearX = args.shearX();
65 m_shearY = args.shearY();
67 m_origPoints = args.origPoints(); //it's a copy
69 m_warpType = args.warpType();
70 m_alpha = args.alpha();
73 m_filter = args.m_filter;
79
80 if (args.m_liquifyWorker) {
82 }
83
88
90}
91
96
97void ToolTransformArgs::setMeshScaleHandles(bool meshScaleHandles)
98{
100
101 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
102 configGroup.writeEntry("meshScaleHandles", meshScaleHandles);
103}
104
111
113 : m_liquifyProperties(new KisLiquifyProperties(*args.m_liquifyProperties.data()))
114{
115 init(args);
116}
117
122
124{
125 if (this == &args) return *this;
126
127 clear();
128
130 init(args);
131
132 return *this;
133}
134
136{
137 return
138 m_mode == other.m_mode &&
140 m_origPoints == other.m_origPoints &&
142 m_warpType == other.m_warpType &&
143 m_alpha == other.m_alpha &&
148 m_aX == other.m_aX &&
149 m_aY == other.m_aY &&
150 m_aZ == other.m_aZ &&
151 m_cameraPos == other.m_cameraPos &&
152 m_scaleX == other.m_scaleX &&
153 m_scaleY == other.m_scaleY &&
154 m_shearX == other.m_shearX &&
155 m_shearY == other.m_shearY &&
163
164 // pointer types
165
167
168 ((m_filter && other.m_filter &&
169 m_filter->id() == other.m_filter->id())
170 || m_filter == other.m_filter) &&
171
172 ((m_liquifyWorker && other.m_liquifyWorker &&
174 || m_liquifyWorker == other.m_liquifyWorker) &&
177}
178
180{
181 if (m_mode != other.m_mode) return false;
182
183 bool result = true;
184
185 if (m_mode == FREE_TRANSFORM) {
186 result &= m_transformedCenter == other.m_transformedCenter;
187 result &= m_originalCenter == other.m_originalCenter;
188 result &= m_scaleX == other.m_scaleX;
189 result &= m_scaleY == other.m_scaleY;
190 result &= m_shearX == other.m_shearX;
191 result &= m_shearY == other.m_shearY;
192 result &= m_boundsRotation == other.m_boundsRotation;
193 result &= m_aX == other.m_aX;
194 result &= m_aY == other.m_aY;
195 result &= m_aZ == other.m_aZ;
196
197 } else if (m_mode == PERSPECTIVE_4POINT) {
198 result &= m_transformedCenter == other.m_transformedCenter;
199 result &= m_originalCenter == other.m_originalCenter;
200 result &= m_scaleX == other.m_scaleX;
201 result &= m_scaleY == other.m_scaleY;
202 result &= m_shearX == other.m_shearX;
203 result &= m_shearY == other.m_shearY;
205
206 } else if(m_mode == WARP || m_mode == CAGE) {
207 result &= m_origPoints == other.m_origPoints;
208 result &= m_transfPoints == other.m_transfPoints;
209
210 } else if (m_mode == LIQUIFY) {
211 result &= m_liquifyProperties &&
214
215 result &=
219
220 } else if (m_mode == MESH) {
221 result &= m_meshTransform == other.m_meshTransform;
222 } else {
223 KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
224 }
225
226 return result;
227}
228
230 QPointF transformedCenter,
231 QPointF originalCenter,
232 QPointF rotationCenterOffset,
233 bool transformAroundRotationCenter,
234 double aX, double aY, double aZ,
235 double scaleX, double scaleY,
236 double shearX, double shearY,
237 double boundsRotation,
239 double alpha,
240 bool defaultPoints,
241 const QString &filterId,
242 int pixelPrecision, int previewPixelPrecision,
243 KisPaintDeviceSP externalSource)
244 : m_mode(mode)
245 , m_defaultPoints(defaultPoints)
246 , m_origPoints {QVector<QPointF>()}
247 , m_transfPoints {QVector<QPointF>()}
248 , m_warpType(warpType)
249 , m_alpha(alpha)
250 , m_transformedCenter(transformedCenter)
251 , m_originalCenter(originalCenter)
252 , m_rotationCenterOffset(rotationCenterOffset)
253 , m_transformAroundRotationCenter(transformAroundRotationCenter)
254 , m_aX(aX)
255 , m_aY(aY)
256 , m_aZ(aZ)
257 , m_scaleX(scaleX)
258 , m_scaleY(scaleY)
259 , m_shearX(shearX)
260 , m_shearY(shearY)
261 , m_boundsRotation(boundsRotation)
262 , m_liquifyProperties(new KisLiquifyProperties())
263 , m_pixelPrecision(pixelPrecision)
264 , m_previewPixelPrecision(previewPixelPrecision)
265 , m_externalSource(externalSource)
266{
268}
269
270
275
276void ToolTransformArgs::translateSrcAndDst(const QPointF &offset)
277{
278 transformSrcAndDst(QTransform::fromTranslate(offset.x(), offset.y()));
279}
280
282{
283 if (m_mode == FREE_TRANSFORM ) {
286
287 QMatrix4x4 m(t);
289 } else if (m_mode == PERSPECTIVE_4POINT) {
292
294
295 } else if(m_mode == WARP || m_mode == CAGE) {
296 for (auto &pt : m_origPoints) {
297 pt = t.map(pt);
298 }
299
300 for (auto &pt : m_transfPoints) {
301 pt = t.map(pt);
302 }
303 } else if (m_mode == LIQUIFY) {
305 m_liquifyWorker->transformSrcAndDst(t);
306 } else if (m_mode == MESH) {
308 } else {
309 KIS_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
310 }
311}
312
313void ToolTransformArgs::translateDstSpace(const QPointF &offset)
314{
316 m_transformedCenter += offset;
317 } else if(m_mode == WARP || m_mode == CAGE) {
318 for (auto &pt : m_transfPoints) {
319 pt += offset;
320 }
321 } else if (m_mode == LIQUIFY) {
323 m_liquifyWorker->translateDstSpace(offset);
324 } else if (m_mode == MESH) {
326 } else {
327 KIS_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
328 }
329}
330
332{
333 if (m_mode == FREE_TRANSFORM) {
335 && m_scaleY == 1 && m_shearX == 0 && m_shearY == 0
336 && m_aX == 0 && m_aY == 0 && m_aZ == 0 && m_boundsRotation == 0);
337 } else if (m_mode == PERSPECTIVE_4POINT) {
339 && m_scaleY == 1 && m_shearX == 0 && m_shearY == 0
340 && m_flattenedPerspectiveTransform.isIdentity());
341 } else if(m_mode == WARP || m_mode == CAGE) {
342 for (int i = 0; i < m_origPoints.size(); ++i)
343 if (m_origPoints[i] != m_transfPoints[i])
344 return false;
345
346 return true;
347 } else if (m_mode == LIQUIFY) {
348 return !m_liquifyWorker || m_liquifyWorker->isIdentity();
349 } else if (m_mode == MESH) {
351 } else {
352 KIS_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
353 return true;
354 }
355}
356
358{
359 return !m_externalSource && isIdentity();
360}
361
363{
364 m_liquifyWorker.reset(new KisLiquifyTransformWorker(srcRect, 0, 8));
365 m_liquifyProperties->loadAndResetMode();
366}
367
372
373void ToolTransformArgs::toXML(QDomElement *e) const
374{
375 e->setAttribute("mode", (int) m_mode);
376
377 QDomDocument doc = e->ownerDocument();
378
380
381 QDomElement freeEl = doc.createElement("free_transform");
382 e->appendChild(freeEl);
383
384 KisDomUtils::saveValue(&freeEl, "transformedCenter", m_transformedCenter);
385 KisDomUtils::saveValue(&freeEl, "originalCenter", m_originalCenter);
386 KisDomUtils::saveValue(&freeEl, "rotationCenterOffset", m_rotationCenterOffset);
387 KisDomUtils::saveValue(&freeEl, "transformAroundRotationCenter", m_transformAroundRotationCenter);
388
389 KisDomUtils::saveValue(&freeEl, "aX", m_aX);
390 KisDomUtils::saveValue(&freeEl, "aY", m_aY);
391 KisDomUtils::saveValue(&freeEl, "aZ", m_aZ);
392
393 KisDomUtils::saveValue(&freeEl, "cameraPos", m_cameraPos);
394
395 KisDomUtils::saveValue(&freeEl, "scaleX", m_scaleX);
396 KisDomUtils::saveValue(&freeEl, "scaleY", m_scaleY);
397
398 KisDomUtils::saveValue(&freeEl, "shearX", m_shearX);
399 KisDomUtils::saveValue(&freeEl, "shearY", m_shearY);
400
401 // bounds rotation is currently not supported by transform masks, so it should be null
402 KisDomUtils::saveValue(&freeEl, "boundsRotation", m_boundsRotation);
403
404 KisDomUtils::saveValue(&freeEl, "keepAspectRatio", m_keepAspectRatio);
405 KisDomUtils::saveValue(&freeEl, "flattenedPerspectiveTransform", m_flattenedPerspectiveTransform);
406
407 KisDomUtils::saveValue(&freeEl, "filterId", m_filter->id());
408
409 } else if (m_mode == WARP || m_mode == CAGE) {
410 QDomElement warpEl = doc.createElement("warp_transform");
411 e->appendChild(warpEl);
412
413 KisDomUtils::saveValue(&warpEl, "defaultPoints", m_defaultPoints);
414 KisDomUtils::saveValue(&warpEl, "originalPoints", m_origPoints);
415 KisDomUtils::saveValue(&warpEl, "transformedPoints", m_transfPoints);
416
417 KisDomUtils::saveValue(&warpEl, "warpType", (int)m_warpType); // limited!
418 KisDomUtils::saveValue(&warpEl, "alpha", m_alpha);
419
420 if(m_mode == CAGE){
421 KisDomUtils::saveValue(&warpEl,"pixelPrecision",m_pixelPrecision);
422 KisDomUtils::saveValue(&warpEl,"previewPixelPrecision",m_previewPixelPrecision);
423 }
424
425 } else if (m_mode == LIQUIFY) {
426 QDomElement liqEl = doc.createElement("liquify_transform");
427 e->appendChild(liqEl);
428
429 m_liquifyProperties->toXML(&liqEl);
430 m_liquifyWorker->toXML(&liqEl);
431 } else if (m_mode == MESH) {
432 QDomElement meshEl = doc.createElement("mesh_transform");
433 e->appendChild(meshEl);
434
435 KisDomUtils::saveValue(&meshEl, "mesh", m_meshTransform);
436 } else {
437 KIS_ASSERT_RECOVER_RETURN(0 && "Unknown transform mode");
438 }
439
440 // m_editTransformPoints should not be saved since it is reset explicitly
441}
442
444{
446
447 int newMode = e.attribute("mode", "0").toInt();
448 if (newMode < 0 || newMode >= N_MODES) return ToolTransformArgs();
449
450 args.m_mode = (TransformMode) newMode;
451
452 // reset explicitly
453 args.m_editTransformPoints = false;
454
455 bool result = false;
456
457 if (args.m_mode == FREE_TRANSFORM || args.m_mode == PERSPECTIVE_4POINT) {
458
459 QDomElement freeEl;
460
461 QString filterId;
462
463 result =
464 KisDomUtils::findOnlyElement(e, "free_transform", &freeEl) &&
465
466 KisDomUtils::loadValue(freeEl, "transformedCenter", &args.m_transformedCenter) &&
467 KisDomUtils::loadValue(freeEl, "originalCenter", &args.m_originalCenter) &&
468 KisDomUtils::loadValue(freeEl, "rotationCenterOffset", &args.m_rotationCenterOffset) &&
469
470 KisDomUtils::loadValue(freeEl, "aX", &args.m_aX) &&
471 KisDomUtils::loadValue(freeEl, "aY", &args.m_aY) &&
472 KisDomUtils::loadValue(freeEl, "aZ", &args.m_aZ) &&
473
474 KisDomUtils::loadValue(freeEl, "cameraPos", &args.m_cameraPos) &&
475
476 KisDomUtils::loadValue(freeEl, "scaleX", &args.m_scaleX) &&
477 KisDomUtils::loadValue(freeEl, "scaleY", &args.m_scaleY) &&
478
479 KisDomUtils::loadValue(freeEl, "shearX", &args.m_shearX) &&
480 KisDomUtils::loadValue(freeEl, "shearY", &args.m_shearY) &&
481
482 KisDomUtils::loadValue(freeEl, "keepAspectRatio", &args.m_keepAspectRatio) &&
483 KisDomUtils::loadValue(freeEl, "flattenedPerspectiveTransform", &args.m_flattenedPerspectiveTransform) &&
484 KisDomUtils::loadValue(freeEl, "filterId", &filterId);
485
486 // transformAroundRotationCenter is a new parameter introduced in Krita 4.0,
487 // so it might be not present in older transform masks
488 if (!KisDomUtils::loadValue(freeEl, "transformAroundRotationCenter", &args.m_transformAroundRotationCenter)) {
490 }
491
492 // bounds rotation is currently not supported by transform masks, so it should be null for them
493 if (!KisDomUtils::loadValue(freeEl, "boundsRotation", &args.m_boundsRotation)) {
494 args.m_boundsRotation = 0.0;
495 }
496
497 if (result) {
499 result = (bool) args.m_filter;
500 }
501
502 } else if (args.m_mode == WARP || args.m_mode == CAGE) {
503 QDomElement warpEl;
504
505 int warpType = 0;
506
507 result =
508 KisDomUtils::findOnlyElement(e, "warp_transform", &warpEl) &&
509
510 KisDomUtils::loadValue(warpEl, "defaultPoints", &args.m_defaultPoints) &&
511
512 KisDomUtils::loadValue(warpEl, "originalPoints", &args.m_origPoints) &&
513 KisDomUtils::loadValue(warpEl, "transformedPoints", &args.m_transfPoints) &&
514
515 KisDomUtils::loadValue(warpEl, "warpType", &warpType) &&
516 KisDomUtils::loadValue(warpEl, "alpha", &args.m_alpha);
517
518 if(args.m_mode == CAGE){
519 // Pixel precision is a parameter introduced in Krita 4.2, so we should
520 // expect it not being present in older files. In case it is not found,
521 // just use the default value initialized by c-tor (that is, do nothing).
522
523 (void) KisDomUtils::loadValue(warpEl, "pixelPrecision", &args.m_pixelPrecision);
524 (void) KisDomUtils::loadValue(warpEl, "previewPixelPrecision", &args.m_previewPixelPrecision);
525 }
526
527 if (result && warpType >= 0 && warpType < KisWarpTransformWorker::N_MODES) {
529 } else {
530 result = false;
531 }
532
533 } else if (args.m_mode == LIQUIFY) {
534 QDomElement liquifyEl;
535
536 result =
537 KisDomUtils::findOnlyElement(e, "liquify_transform", &liquifyEl);
538
541 } else if (args.m_mode == MESH) {
542 QDomElement meshEl;
543
544 result =
545 KisDomUtils::findOnlyElement(e, "mesh_transform", &meshEl);
546
547 result &= KisDomUtils::loadValue(meshEl, "mesh", &args.m_meshTransform);
548
549 } else {
550 KIS_ASSERT_RECOVER_NOOP(0 && "Unknown transform mode");
551 }
552
554 args = ToolTransformArgs();
555 }
556
557 return args;
558}
559
565
567{
568 QScopedPointer<ToolTransformArgs> tempTransformation(
570
571 *this = *tempTransformation;
572 m_continuedTransformation.swap(tempTransformation);
573}
574
579
584
589
591{
592 return m_meshShowHandles;
593}
594
596{
598
599 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
600 configGroup.writeEntry("meshShowHandles", value);
601}
602
607
609{
611
612 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KisToolTransform");
613 configGroup.writeEntry("meshSymmetricalHandles", value);
614}
615
617{
618 const QTransform t = QTransform::fromScale(scale, scale);
619
620 if (m_mode == FREE_TRANSFORM ) {
623
624 // we need to scale Z-coordinate of the camera pos as well,
625 // so we cannot just do `QMatrix4x4 m(t)`.
626 QMatrix4x4 m;
627 m.scale(scale);
629 } else {
631 }
632}
float value(const T *src, size_t ch)
KisBezierTransformMeshDetail::KisBezierTransformMesh KisBezierTransformMesh
void transformSrcAndDst(const QTransform &t)
void translate(const QPointF &offset)
static KisFilterStrategyRegistry * instance()
static KisLiquifyProperties fromXML(const QDomElement &e)
enum KisWarpTransformWorker::WarpType_ WarpType
const T value(const QString &id) const
void toXML(QDomElement *e) const
QPointF transformedCenter() const
void init(const ToolTransformArgs &args)
void scale3dSrcAndDst(qreal scale)
KisFilterStrategy * m_filter
bool meshScaleHandles() const
void setFilterId(const QString &id)
void initLiquifyTransformMode(const QRect &srcRect)
KisToolChangesTrackerData * clone() const override
const QVector< QPointF > & origPoints() const
KisPaintDeviceSP m_externalSource
QScopedPointer< ToolTransformArgs > m_continuedTransformation
void setTransformAroundRotationCenter(bool value)
bool transformAroundRotationCenter() const
int previewPixelPrecision() const
QVector< QPointF > m_transfPoints
void transformSrcAndDst(const QTransform &t)
KisWarpTransformWorker::WarpType warpType() const
void translateSrcAndDst(const QPointF &offset)
void setMeshShowHandles(bool value)
void saveLiquifyTransformMode() const
void setMeshScaleHandles(bool meshScaleHandles)
bool meshSymmetricalHandles() const
QVector< QPointF > m_origPoints
QPointF originalCenter() const
void setMeshSymmetricalHandles(bool meshSymmetricalHandles)
bool operator==(const ToolTransformArgs &other) const
QPointF rotationCenterOffset() const
KisWarpTransformWorker::WarpType m_warpType
ToolTransformArgs & operator=(const ToolTransformArgs &args)
const QVector< QPointF > & transfPoints() const
const KisBezierTransformMesh * meshTransform() const
void translateDstSpace(const QPointF &offset)
double boundsRotation() const
bool isSameMode(const ToolTransformArgs &other) const
QSharedPointer< KisLiquifyProperties > m_liquifyProperties
QTransform m_flattenedPerspectiveTransform
QString filterId() const
static ToolTransformArgs fromXML(const QDomElement &e)
TransformMode mode() const
QScopedPointer< KisLiquifyTransformWorker > m_liquifyWorker
KisPaintDeviceSP externalSource() const
KisBezierTransformMesh m_meshTransform
const ToolTransformArgs * continuedTransform() const
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
void saveValue(QDomElement *parent, const QString &tag, const QSize &size)
bool findOnlyElement(const QDomElement &parent, const QString &tag, QDomElement *el, QStringList *errorMessages)
bool loadValue(const QDomElement &e, float *v)
static KisLiquifyTransformWorker * fromXML(const QDomElement &e)