File indexing completed on 2024-12-22 04:16:59

0001 /*
0002  *  tool_transform_args.h - part of Krita
0003  *
0004  *  SPDX-FileCopyrightText: 2010 Marc Pegon <pe.marc@free.fr>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "tool_transform_args.h"
0010 
0011 #include <QDomElement>
0012 
0013 #include <ksharedconfig.h>
0014 #include <kconfig.h>
0015 #include <kconfiggroup.h>
0016 
0017 #include "kis_liquify_transform_worker.h"
0018 #include "kis_dom_utils.h"
0019 #include <QMatrix4x4>
0020 
0021 
0022 ToolTransformArgs::ToolTransformArgs()
0023     : m_liquifyProperties(new KisLiquifyProperties())
0024 {
0025     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("KisToolTransform");
0026     QString savedFilterId = configGroup.readEntry("filterId", "Bicubic");
0027     setFilterId(savedFilterId);
0028     m_transformAroundRotationCenter = configGroup.readEntry("transformAroundRotationCenter", "0").toInt();
0029     m_meshShowHandles = configGroup.readEntry("meshShowHandles", true);
0030     m_meshSymmetricalHandles = configGroup.readEntry("meshSymmetricalHandles", true);
0031     m_meshScaleHandles = configGroup.readEntry("meshScaleHandles", false);
0032 }
0033 
0034 void ToolTransformArgs::setFilterId(const QString &id) {
0035     m_filter = KisFilterStrategyRegistry::instance()->value(id);
0036 
0037     if (m_filter) {
0038         KConfigGroup configGroup =  KSharedConfig::openConfig()->group("KisToolTransform");
0039         configGroup.writeEntry("filterId", id);
0040     }
0041 }
0042 
0043 void ToolTransformArgs::setTransformAroundRotationCenter(bool value)
0044 {
0045     m_transformAroundRotationCenter = value;
0046 
0047     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("KisToolTransform");
0048     configGroup.writeEntry("transformAroundRotationCenter", int(value));
0049 }
0050 
0051 void ToolTransformArgs::init(const ToolTransformArgs& args)
0052 {
0053     m_mode = args.mode();
0054     m_transformedCenter = args.transformedCenter();
0055     m_originalCenter = args.originalCenter();
0056     m_rotationCenterOffset = args.rotationCenterOffset();
0057     m_transformAroundRotationCenter = args.transformAroundRotationCenter();
0058     m_cameraPos = args.m_cameraPos;
0059     m_aX = args.aX();
0060     m_aY = args.aY();
0061     m_aZ = args.aZ();
0062     m_scaleX = args.scaleX();
0063     m_scaleY = args.scaleY();
0064     m_shearX = args.shearX();
0065     m_shearY = args.shearY();
0066     m_origPoints = args.origPoints(); //it's a copy
0067     m_transfPoints = args.transfPoints();
0068     m_warpType = args.warpType();
0069     m_alpha = args.alpha();
0070     m_defaultPoints = args.defaultPoints();
0071     m_keepAspectRatio = args.keepAspectRatio();
0072     m_filter = args.m_filter;
0073     m_flattenedPerspectiveTransform = args.m_flattenedPerspectiveTransform;
0074     m_editTransformPoints = args.m_editTransformPoints;
0075     m_pixelPrecision = args.pixelPrecision();
0076     m_previewPixelPrecision = args.previewPixelPrecision();
0077     m_externalSource = args.externalSource();
0078 
0079     if (args.m_liquifyWorker) {
0080         m_liquifyWorker.reset(new KisLiquifyTransformWorker(*args.m_liquifyWorker.data()));
0081     }
0082 
0083     m_meshTransform = args.m_meshTransform;
0084     m_meshShowHandles = args.m_meshShowHandles;
0085     m_meshSymmetricalHandles = args.m_meshSymmetricalHandles;
0086     m_meshScaleHandles = args.m_meshScaleHandles;
0087 
0088     m_continuedTransformation.reset(args.m_continuedTransformation ? new ToolTransformArgs(*args.m_continuedTransformation) : 0);
0089 }
0090 
0091 bool ToolTransformArgs::meshScaleHandles() const
0092 {
0093     return m_meshScaleHandles;
0094 }
0095 
0096 void ToolTransformArgs::setMeshScaleHandles(bool meshScaleHandles)
0097 {
0098     m_meshScaleHandles = meshScaleHandles;
0099 
0100     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("KisToolTransform");
0101     configGroup.writeEntry("meshScaleHandles", meshScaleHandles);
0102 }
0103 
0104 void ToolTransformArgs::clear()
0105 {
0106     m_origPoints.clear();
0107     m_transfPoints.clear();
0108     m_meshTransform = KisBezierTransformMesh();
0109 }
0110 
0111 ToolTransformArgs::ToolTransformArgs(const ToolTransformArgs& args)
0112     : m_liquifyProperties(new KisLiquifyProperties(*args.m_liquifyProperties.data()))
0113 {
0114     init(args);
0115 }
0116 
0117 KisToolChangesTrackerData *ToolTransformArgs::clone() const
0118 {
0119     return new ToolTransformArgs(*this);
0120 }
0121 
0122 ToolTransformArgs& ToolTransformArgs::operator=(const ToolTransformArgs& args)
0123 {
0124     if (this == &args) return *this;
0125 
0126     clear();
0127 
0128     m_liquifyProperties.reset(new KisLiquifyProperties(*args.m_liquifyProperties.data()));
0129     init(args);
0130 
0131     return *this;
0132 }
0133 
0134 bool ToolTransformArgs::operator==(const ToolTransformArgs& other) const
0135 {
0136     return
0137         m_mode == other.m_mode &&
0138         m_defaultPoints == other.m_defaultPoints &&
0139         m_origPoints == other.m_origPoints &&
0140         m_transfPoints == other.m_transfPoints &&
0141         m_warpType == other.m_warpType &&
0142         m_alpha == other.m_alpha &&
0143         m_transformedCenter == other.m_transformedCenter &&
0144         m_originalCenter == other.m_originalCenter &&
0145         m_rotationCenterOffset == other.m_rotationCenterOffset &&
0146         m_transformAroundRotationCenter == other.m_transformAroundRotationCenter &&
0147         m_aX == other.m_aX &&
0148         m_aY == other.m_aY &&
0149         m_aZ == other.m_aZ &&
0150         m_cameraPos == other.m_cameraPos &&
0151         m_scaleX == other.m_scaleX &&
0152         m_scaleY == other.m_scaleY &&
0153         m_shearX == other.m_shearX &&
0154         m_shearY == other.m_shearY &&
0155         m_keepAspectRatio == other.m_keepAspectRatio &&
0156         m_flattenedPerspectiveTransform == other.m_flattenedPerspectiveTransform &&
0157         m_editTransformPoints == other.m_editTransformPoints &&
0158         (m_liquifyProperties == other.m_liquifyProperties ||
0159          *m_liquifyProperties == *other.m_liquifyProperties) &&
0160         m_meshTransform == other.m_meshTransform &&
0161 
0162         // pointer types
0163 
0164         m_externalSource == other.m_externalSource &&
0165 
0166         ((m_filter && other.m_filter &&
0167           m_filter->id() == other.m_filter->id())
0168          || m_filter == other.m_filter) &&
0169 
0170         ((m_liquifyWorker && other.m_liquifyWorker &&
0171           *m_liquifyWorker == *other.m_liquifyWorker)
0172          || m_liquifyWorker == other.m_liquifyWorker) &&
0173             m_pixelPrecision == other.m_pixelPrecision &&
0174             m_previewPixelPrecision == other.m_previewPixelPrecision;
0175 }
0176 
0177 bool ToolTransformArgs::isSameMode(const ToolTransformArgs& other) const
0178 {
0179     if (m_mode != other.m_mode) return false;
0180 
0181     bool result = true;
0182 
0183     if (m_mode == FREE_TRANSFORM) {
0184         result &= m_transformedCenter == other.m_transformedCenter;
0185         result &= m_originalCenter == other.m_originalCenter;
0186         result &= m_scaleX == other.m_scaleX;
0187         result &= m_scaleY == other.m_scaleY;
0188         result &= m_shearX == other.m_shearX;
0189         result &= m_shearY == other.m_shearY;
0190         result &= m_aX == other.m_aX;
0191         result &= m_aY == other.m_aY;
0192         result &= m_aZ == other.m_aZ;
0193 
0194     } else if (m_mode == PERSPECTIVE_4POINT) {
0195         result &= m_transformedCenter == other.m_transformedCenter;
0196         result &= m_originalCenter == other.m_originalCenter;
0197         result &= m_scaleX == other.m_scaleX;
0198         result &= m_scaleY == other.m_scaleY;
0199         result &= m_shearX == other.m_shearX;
0200         result &= m_shearY == other.m_shearY;
0201         result &= m_flattenedPerspectiveTransform == other.m_flattenedPerspectiveTransform;
0202 
0203     } else if(m_mode == WARP || m_mode == CAGE) {
0204         result &= m_origPoints == other.m_origPoints;
0205         result &= m_transfPoints == other.m_transfPoints;
0206 
0207     } else if (m_mode == LIQUIFY) {
0208         result &= m_liquifyProperties &&
0209             (m_liquifyProperties == other.m_liquifyProperties ||
0210              *m_liquifyProperties == *other.m_liquifyProperties);
0211 
0212         result &=
0213             (m_liquifyWorker && other.m_liquifyWorker &&
0214              *m_liquifyWorker == *other.m_liquifyWorker)
0215             || m_liquifyWorker == other.m_liquifyWorker;
0216 
0217     } else if (m_mode == MESH) {
0218         result &= m_meshTransform == other.m_meshTransform;
0219     } else {
0220         KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
0221     }
0222 
0223     return result;
0224 }
0225 
0226 ToolTransformArgs::ToolTransformArgs(TransformMode mode,
0227                                      QPointF transformedCenter,
0228                                      QPointF originalCenter,
0229                                      QPointF rotationCenterOffset,
0230                                      bool transformAroundRotationCenter,
0231                                      double aX, double aY, double aZ,
0232                                      double scaleX, double scaleY,
0233                                      double shearX, double shearY,
0234                                      KisWarpTransformWorker::WarpType warpType,
0235                                      double alpha,
0236                                      bool defaultPoints,
0237                                      const QString &filterId,
0238                                      int pixelPrecision, int previewPixelPrecision,
0239                                      KisPaintDeviceSP externalSource)
0240     : m_mode(mode)
0241     , m_defaultPoints(defaultPoints)
0242     , m_origPoints {QVector<QPointF>()}
0243     , m_transfPoints {QVector<QPointF>()}
0244     , m_warpType(warpType)
0245     , m_alpha(alpha)
0246     , m_transformedCenter(transformedCenter)
0247     , m_originalCenter(originalCenter)
0248     , m_rotationCenterOffset(rotationCenterOffset)
0249     , m_transformAroundRotationCenter(transformAroundRotationCenter)
0250     , m_aX(aX)
0251     , m_aY(aY)
0252     , m_aZ(aZ)
0253     , m_scaleX(scaleX)
0254     , m_scaleY(scaleY)
0255     , m_shearX(shearX)
0256     , m_shearY(shearY)
0257     , m_liquifyProperties(new KisLiquifyProperties())
0258     , m_pixelPrecision(pixelPrecision)
0259     , m_previewPixelPrecision(previewPixelPrecision)
0260     , m_externalSource(externalSource)
0261 {
0262     setFilterId(filterId);
0263 }
0264 
0265 
0266 ToolTransformArgs::~ToolTransformArgs()
0267 {
0268     clear();
0269 }
0270 
0271 void ToolTransformArgs::translateSrcAndDst(const QPointF &offset)
0272 {
0273     transformSrcAndDst(QTransform::fromTranslate(offset.x(), offset.y()));
0274 }
0275 
0276 void ToolTransformArgs::transformSrcAndDst(const QTransform &t)
0277 {
0278     if (m_mode == FREE_TRANSFORM ) {
0279         m_originalCenter = t.map(m_originalCenter);
0280         m_transformedCenter = t.map(m_transformedCenter);
0281 
0282         QMatrix4x4 m(t);
0283         m_cameraPos = m * m_cameraPos;
0284     } else if (m_mode == PERSPECTIVE_4POINT) {
0285         m_originalCenter = t.map(m_originalCenter);
0286         m_transformedCenter = t.map(m_transformedCenter);
0287 
0288         m_flattenedPerspectiveTransform = t.inverted() * m_flattenedPerspectiveTransform * t;
0289 
0290     } else if(m_mode == WARP || m_mode == CAGE) {
0291         for (auto &pt : m_origPoints) {
0292             pt = t.map(pt);
0293         }
0294 
0295         for (auto &pt : m_transfPoints) {
0296             pt = t.map(pt);
0297         }
0298     } else if (m_mode == LIQUIFY) {
0299         KIS_ASSERT_RECOVER_RETURN(m_liquifyWorker);
0300         m_liquifyWorker->transformSrcAndDst(t);
0301     } else if (m_mode == MESH) {
0302         m_meshTransform.transformSrcAndDst(t);
0303     } else {
0304         KIS_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
0305     }
0306 }
0307 
0308 void ToolTransformArgs::translateDstSpace(const QPointF &offset)
0309 {
0310     if (m_mode == FREE_TRANSFORM || m_mode == PERSPECTIVE_4POINT) {
0311         m_transformedCenter += offset;
0312     } else if(m_mode == WARP || m_mode == CAGE) {
0313         for (auto &pt : m_transfPoints) {
0314             pt += offset;
0315         }
0316     } else if (m_mode == LIQUIFY) {
0317         KIS_ASSERT_RECOVER_RETURN(m_liquifyWorker);
0318         m_liquifyWorker->translateDstSpace(offset);
0319     } else if (m_mode == MESH) {
0320         m_meshTransform.translate(offset);
0321     } else {
0322         KIS_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
0323     }
0324 }
0325 
0326 bool ToolTransformArgs::isIdentity() const
0327 {
0328     if (m_mode == FREE_TRANSFORM) {
0329         return (m_transformedCenter == m_originalCenter && m_scaleX == 1
0330                 && m_scaleY == 1 && m_shearX == 0 && m_shearY == 0
0331                 && m_aX == 0 && m_aY == 0 && m_aZ == 0);
0332     } else if (m_mode == PERSPECTIVE_4POINT) {
0333             return (m_transformedCenter == m_originalCenter && m_scaleX == 1
0334                     && m_scaleY == 1 && m_shearX == 0 && m_shearY == 0
0335                     && m_flattenedPerspectiveTransform.isIdentity());
0336     } else if(m_mode == WARP || m_mode == CAGE) {
0337         for (int i = 0; i < m_origPoints.size(); ++i)
0338             if (m_origPoints[i] != m_transfPoints[i])
0339                 return false;
0340 
0341         return true;
0342     } else if (m_mode == LIQUIFY) {
0343         return !m_liquifyWorker || m_liquifyWorker->isIdentity();
0344     } else if (m_mode == MESH) {
0345         return m_meshTransform.isIdentity();
0346     } else {
0347         KIS_ASSERT_RECOVER_NOOP(0 && "unknown transform mode");
0348         return true;
0349     }
0350 }
0351 
0352 bool ToolTransformArgs::isUnchanging() const
0353 {
0354     return !m_externalSource && isIdentity();
0355 }
0356 
0357 void ToolTransformArgs::initLiquifyTransformMode(const QRect &srcRect)
0358 {
0359     m_liquifyWorker.reset(new KisLiquifyTransformWorker(srcRect, 0, 8));
0360     m_liquifyProperties->loadAndResetMode();
0361 }
0362 
0363 void ToolTransformArgs::saveLiquifyTransformMode() const
0364 {
0365     m_liquifyProperties->saveMode();
0366 }
0367 
0368 void ToolTransformArgs::toXML(QDomElement *e) const
0369 {
0370     e->setAttribute("mode", (int) m_mode);
0371 
0372     QDomDocument doc = e->ownerDocument();
0373 
0374     if (m_mode == FREE_TRANSFORM || m_mode == PERSPECTIVE_4POINT) {
0375 
0376         QDomElement freeEl = doc.createElement("free_transform");
0377         e->appendChild(freeEl);
0378 
0379         KisDomUtils::saveValue(&freeEl, "transformedCenter", m_transformedCenter);
0380         KisDomUtils::saveValue(&freeEl, "originalCenter", m_originalCenter);
0381         KisDomUtils::saveValue(&freeEl, "rotationCenterOffset", m_rotationCenterOffset);
0382         KisDomUtils::saveValue(&freeEl, "transformAroundRotationCenter", m_transformAroundRotationCenter);
0383 
0384         KisDomUtils::saveValue(&freeEl, "aX", m_aX);
0385         KisDomUtils::saveValue(&freeEl, "aY", m_aY);
0386         KisDomUtils::saveValue(&freeEl, "aZ", m_aZ);
0387 
0388         KisDomUtils::saveValue(&freeEl, "cameraPos", m_cameraPos);
0389 
0390         KisDomUtils::saveValue(&freeEl, "scaleX", m_scaleX);
0391         KisDomUtils::saveValue(&freeEl, "scaleY", m_scaleY);
0392 
0393         KisDomUtils::saveValue(&freeEl, "shearX", m_shearX);
0394         KisDomUtils::saveValue(&freeEl, "shearY", m_shearY);
0395 
0396         KisDomUtils::saveValue(&freeEl, "keepAspectRatio", m_keepAspectRatio);
0397         KisDomUtils::saveValue(&freeEl, "flattenedPerspectiveTransform", m_flattenedPerspectiveTransform);
0398 
0399         KisDomUtils::saveValue(&freeEl, "filterId", m_filter->id());
0400 
0401     } else if (m_mode == WARP || m_mode == CAGE) {
0402         QDomElement warpEl = doc.createElement("warp_transform");
0403         e->appendChild(warpEl);
0404 
0405         KisDomUtils::saveValue(&warpEl, "defaultPoints", m_defaultPoints);
0406         KisDomUtils::saveValue(&warpEl, "originalPoints", m_origPoints);
0407         KisDomUtils::saveValue(&warpEl, "transformedPoints", m_transfPoints);
0408 
0409         KisDomUtils::saveValue(&warpEl, "warpType", (int)m_warpType); // limited!
0410         KisDomUtils::saveValue(&warpEl, "alpha", m_alpha);
0411 
0412         if(m_mode == CAGE){
0413             KisDomUtils::saveValue(&warpEl,"pixelPrecision",m_pixelPrecision);
0414             KisDomUtils::saveValue(&warpEl,"previewPixelPrecision",m_previewPixelPrecision);
0415         }
0416 
0417     } else if (m_mode == LIQUIFY) {
0418         QDomElement liqEl = doc.createElement("liquify_transform");
0419         e->appendChild(liqEl);
0420 
0421         m_liquifyProperties->toXML(&liqEl);
0422         m_liquifyWorker->toXML(&liqEl);
0423     } else if (m_mode == MESH) {
0424         QDomElement meshEl = doc.createElement("mesh_transform");
0425         e->appendChild(meshEl);
0426 
0427         KisDomUtils::saveValue(&meshEl, "mesh", m_meshTransform);
0428     } else {
0429         KIS_ASSERT_RECOVER_RETURN(0 && "Unknown transform mode");
0430     }
0431 
0432     // m_editTransformPoints should not be saved since it is reset explicitly
0433 }
0434 
0435 ToolTransformArgs ToolTransformArgs::fromXML(const QDomElement &e)
0436 {
0437     ToolTransformArgs args;
0438 
0439     int newMode = e.attribute("mode", "0").toInt();
0440     if (newMode < 0 || newMode >= N_MODES) return ToolTransformArgs();
0441 
0442     args.m_mode = (TransformMode) newMode;
0443 
0444     // reset explicitly
0445     args.m_editTransformPoints = false;
0446 
0447     bool result = false;
0448 
0449     if (args.m_mode == FREE_TRANSFORM || args.m_mode == PERSPECTIVE_4POINT) {
0450 
0451         QDomElement freeEl;
0452 
0453         QString filterId;
0454 
0455         result =
0456             KisDomUtils::findOnlyElement(e, "free_transform", &freeEl) &&
0457 
0458             KisDomUtils::loadValue(freeEl, "transformedCenter", &args.m_transformedCenter) &&
0459             KisDomUtils::loadValue(freeEl, "originalCenter", &args.m_originalCenter) &&
0460             KisDomUtils::loadValue(freeEl, "rotationCenterOffset", &args.m_rotationCenterOffset) &&
0461 
0462             KisDomUtils::loadValue(freeEl, "aX", &args.m_aX) &&
0463             KisDomUtils::loadValue(freeEl, "aY", &args.m_aY) &&
0464             KisDomUtils::loadValue(freeEl, "aZ", &args.m_aZ) &&
0465 
0466             KisDomUtils::loadValue(freeEl, "cameraPos", &args.m_cameraPos) &&
0467 
0468             KisDomUtils::loadValue(freeEl, "scaleX", &args.m_scaleX) &&
0469             KisDomUtils::loadValue(freeEl, "scaleY", &args.m_scaleY) &&
0470 
0471             KisDomUtils::loadValue(freeEl, "shearX", &args.m_shearX) &&
0472             KisDomUtils::loadValue(freeEl, "shearY", &args.m_shearY) &&
0473 
0474             KisDomUtils::loadValue(freeEl, "keepAspectRatio", &args.m_keepAspectRatio) &&
0475             KisDomUtils::loadValue(freeEl, "flattenedPerspectiveTransform", &args.m_flattenedPerspectiveTransform) &&
0476             KisDomUtils::loadValue(freeEl, "filterId", &filterId);
0477 
0478         // transformAroundRotationCenter is a new parameter introduced in Krita 4.0,
0479         // so it might be not present in older transform masks
0480         if (!KisDomUtils::loadValue(freeEl, "transformAroundRotationCenter", &args.m_transformAroundRotationCenter)) {
0481             args.m_transformAroundRotationCenter = false;
0482         }
0483 
0484         if (result) {
0485             args.m_filter = KisFilterStrategyRegistry::instance()->value(filterId);
0486             result = (bool) args.m_filter;
0487         }
0488 
0489     } else if (args.m_mode == WARP || args.m_mode == CAGE) {
0490         QDomElement warpEl;
0491 
0492         int warpType = 0;
0493 
0494         result =
0495             KisDomUtils::findOnlyElement(e, "warp_transform", &warpEl) &&
0496 
0497             KisDomUtils::loadValue(warpEl, "defaultPoints", &args.m_defaultPoints) &&
0498 
0499             KisDomUtils::loadValue(warpEl, "originalPoints", &args.m_origPoints) &&
0500             KisDomUtils::loadValue(warpEl, "transformedPoints", &args.m_transfPoints) &&
0501 
0502             KisDomUtils::loadValue(warpEl, "warpType", &warpType) &&
0503             KisDomUtils::loadValue(warpEl, "alpha", &args.m_alpha);
0504 
0505         if(args.m_mode == CAGE){
0506             // Pixel precision is a parameter introduced in Krita 4.2, so we should
0507             // expect it not being present in older files. In case it is not found,
0508             // just use the default value initialized by c-tor (that is, do nothing).
0509 
0510             (void) KisDomUtils::loadValue(warpEl, "pixelPrecision", &args.m_pixelPrecision);
0511             (void) KisDomUtils::loadValue(warpEl, "previewPixelPrecision", &args.m_previewPixelPrecision);
0512         }
0513 
0514         if (result && warpType >= 0 && warpType < KisWarpTransformWorker::N_MODES) {
0515             args.m_warpType = (KisWarpTransformWorker::WarpType_) warpType;
0516         } else {
0517             result = false;
0518         }
0519 
0520     } else if (args.m_mode == LIQUIFY) {
0521         QDomElement liquifyEl;
0522 
0523         result =
0524             KisDomUtils::findOnlyElement(e, "liquify_transform", &liquifyEl);
0525 
0526         *args.m_liquifyProperties = KisLiquifyProperties::fromXML(e);
0527         args.m_liquifyWorker.reset(KisLiquifyTransformWorker::fromXML(e));
0528     } else if (args.m_mode == MESH) {
0529         QDomElement meshEl;
0530 
0531         result =
0532             KisDomUtils::findOnlyElement(e, "mesh_transform", &meshEl);
0533 
0534         result &= KisDomUtils::loadValue(meshEl, "mesh", &args.m_meshTransform);
0535 
0536     } else {
0537         KIS_ASSERT_RECOVER_NOOP(0 && "Unknown transform mode");
0538     }
0539 
0540     KIS_SAFE_ASSERT_RECOVER(result) {
0541         args = ToolTransformArgs();
0542     }
0543 
0544     return args;
0545 }
0546 
0547 void ToolTransformArgs::saveContinuedState()
0548 {
0549     m_continuedTransformation.reset();
0550     m_continuedTransformation.reset(new ToolTransformArgs(*this));
0551 }
0552 
0553 void ToolTransformArgs::restoreContinuedState()
0554 {
0555     QScopedPointer<ToolTransformArgs> tempTransformation(
0556         new ToolTransformArgs(*m_continuedTransformation));
0557 
0558     *this = *tempTransformation;
0559     m_continuedTransformation.swap(tempTransformation);
0560 }
0561 
0562 const ToolTransformArgs* ToolTransformArgs::continuedTransform() const
0563 {
0564     return m_continuedTransformation.data();
0565 }
0566 
0567 const KisBezierTransformMesh *ToolTransformArgs::meshTransform() const
0568 {
0569     return &m_meshTransform;
0570 }
0571 
0572 KisBezierTransformMesh *ToolTransformArgs::meshTransform()
0573 {
0574     return &m_meshTransform;
0575 }
0576 
0577 bool ToolTransformArgs::meshShowHandles() const
0578 {
0579     return m_meshShowHandles;
0580 }
0581 
0582 void ToolTransformArgs::setMeshShowHandles(bool value)
0583 {
0584     m_meshShowHandles = value;
0585 
0586     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("KisToolTransform");
0587     configGroup.writeEntry("meshShowHandles", value);
0588 }
0589 
0590 bool ToolTransformArgs::meshSymmetricalHandles() const
0591 {
0592     return m_meshSymmetricalHandles;
0593 }
0594 
0595 void ToolTransformArgs::setMeshSymmetricalHandles(bool value)
0596 {
0597     m_meshSymmetricalHandles = value;
0598 
0599     KConfigGroup configGroup =  KSharedConfig::openConfig()->group("KisToolTransform");
0600     configGroup.writeEntry("meshSymmetricalHandles", value);
0601 }
0602 
0603 void ToolTransformArgs::scale3dSrcAndDst(qreal scale)
0604 {
0605     const QTransform t = QTransform::fromScale(scale, scale);
0606 
0607     if (m_mode == FREE_TRANSFORM ) {
0608         m_originalCenter = t.map(m_originalCenter);
0609         m_transformedCenter = t.map(m_transformedCenter);
0610 
0611         // we need to scale Z-coordinate of the camera pos as well,
0612         // so we cannot just do `QMatrix4x4 m(t)`.
0613         QMatrix4x4 m;
0614         m.scale(scale);
0615         m_cameraPos = m * m_cameraPos;
0616     } else {
0617         transformSrcAndDst(t);
0618     }
0619 }