[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [calligra/krita-chili-kazakov] krita: Implemented preview of the Cage Transform
From:       Dmitry Kazakov <dimula73 () gmail ! com>
Date:       2014-09-19 9:28:25
Message-ID: E1XUuUL-0006MY-EP () scm ! kde ! org
[Download RAW message or body]

Git commit ff9a841fe1fc7906da7fd071cbbb63748ac4deaf by Dmitry Kazakov.
Committed on 19/09/2014 at 09:28.
Pushed by dkazakov into branch 'krita-chili-kazakov'.

Implemented preview of the Cage Transform

Still in TODO list:
1) Fix resetting edit points mode when switching between warp and cage
   transforms
2) Add extrapolation at the borders of the cage
3) Fix a random assert in the cage adjusting algorithm

M  +11   -5    krita/image/kis_algebra_2d.cpp
M  +2    -1    krita/image/kis_algebra_2d.h
M  +117  -33   krita/image/kis_cage_transform_worker.cpp
M  +8    -0    krita/image/kis_cage_transform_worker.h
M  +20   -0    krita/image/kis_global.h
M  +2    -2    krita/image/kis_grid_interpolation_tools.h
M  +5    -5    krita/image/kis_warptransform_worker.cc
M  +40   -12   krita/image/tests/kis_cage_transform_worker_test.cpp
M  +1    -0    krita/image/tests/kis_cage_transform_worker_test.h
M  +20   -0    krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp
M  +7    -0    krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.h
M  +21   -7    krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp
M  +7    -0    krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.h

http://commits.kde.org/calligra/ff9a841fe1fc7906da7fd071cbbb63748ac4deaf

diff --git a/krita/image/kis_algebra_2d.cpp b/krita/image/kis_algebra_2d.cpp
index ed6d15a..cbc9791 100644
--- a/krita/image/kis_algebra_2d.cpp
+++ b/krita/image/kis_algebra_2d.cpp
@@ -19,11 +19,10 @@
 #include "kis_algebra_2d.h"
 
 #include <kis_debug.h>
-#include <QPolygonF>
 
 namespace KisAlgebra2D {
 
-void KRITAIMAGE_EXPORT adjustIfOnPolygonBoundary(const QVector<QPointF> &poly, int \
polygonDirection, QPointF *pt) +void KRITAIMAGE_EXPORT \
adjustIfOnPolygonBoundary(const QPolygonF &poly, int polygonDirection, QPointF *pt)  \
{  const int numPoints = poly.size();
     for (int i = 0; i < numPoints; i++) {
@@ -44,10 +43,17 @@ void KRITAIMAGE_EXPORT adjustIfOnPolygonBoundary(const \
QVector<QPointF> &poly, i  isInRange(pt->x(), p0.x(), p1.x()) &&
             isInRange(pt->y(), p0.y(), p1.y())) {
 
-            QPointF salt = 1.0e-4 * inwardUnitNormal(edge, polygonDirection);
-            *pt += salt;
+            QPointF salt = 1.0e-3 * inwardUnitNormal(edge, polygonDirection);
 
-            KIS_ASSERT_RECOVER_NOOP(QPolygonF(poly).containsPoint(*pt, \
Qt::OddEvenFill)); +            QPointF t1 = *pt + salt;
+            QPointF t2 = *pt - salt;
+
+            if (poly.contains(t1)) {
+                *pt = t1;
+            } else {
+                KIS_ASSERT_RECOVER_NOOP(poly.containsPoint(t2, Qt::OddEvenFill));
+                *pt = t2;
+            }
         }
     }
 }
diff --git a/krita/image/kis_algebra_2d.h b/krita/image/kis_algebra_2d.h
index d2ce332..5c0b370 100644
--- a/krita/image/kis_algebra_2d.h
+++ b/krita/image/kis_algebra_2d.h
@@ -22,6 +22,7 @@
 #include <QPoint>
 #include <QPointF>
 #include <QVector>
+#include <QPolygonF>
 #include <cmath>
 #include <kis_global.h>
 
@@ -118,7 +119,7 @@ bool isInRange(T x, T a, T b) {
     return qAbs(x - a) <= length && qAbs(x - b) <= length;
 }
 
-void KRITAIMAGE_EXPORT adjustIfOnPolygonBoundary(const QVector<QPointF> &poly, int \
polygonDirection, QPointF *pt); +void KRITAIMAGE_EXPORT \
adjustIfOnPolygonBoundary(const QPolygonF &poly, int polygonDirection, QPointF *pt);  \
  }
 
diff --git a/krita/image/kis_cage_transform_worker.cpp \
b/krita/image/kis_cage_transform_worker.cpp index 6c39354..984e063 100644
--- a/krita/image/kis_cage_transform_worker.cpp
+++ b/krita/image/kis_cage_transform_worker.cpp
@@ -22,6 +22,8 @@
 #include "kis_green_coordinates_math.h"
 #include "kis_algebra_2d.h"
 
+#include <QPainter>
+
 #include "KoColor.h"
 #include "kis_selection.h"
 #include "kis_painter.h"
@@ -41,6 +43,10 @@ struct KisCageTransformWorker::Private
     }
 
     KisPaintDeviceSP dev;
+
+    QImage srcImage;
+    QPointF srcImageOffset;
+
     QVector<QPointF> origCage;
     QVector<QPointF> transfCage;
     KoUpdater *progress;
@@ -52,6 +58,12 @@ struct KisCageTransformWorker::Private
     KisGreenCoordinatesMath cage;
 
     QSize gridSize;
+
+    QVector<QPointF> calculateTransformedPoints();
+
+    template <class PolygonOp>
+    void iterateThroughGrid(PolygonOp polygonOp,
+                       const QVector<QPointF> &transformedPoints);
 };
 
 KisCageTransformWorker::KisCageTransformWorker(KisPaintDeviceSP dev,
@@ -62,6 +74,17 @@ KisCageTransformWorker::KisCageTransformWorker(KisPaintDeviceSP \
dev,  {
 }
 
+KisCageTransformWorker::KisCageTransformWorker(const QImage &srcImage,
+                                               const QPointF &srcImageOffset,
+                                               const QVector<QPointF> &origCage,
+                                               KoUpdater *progress,
+                                               int pixelPrecision)
+    : m_d(new Private(0, origCage, progress, pixelPrecision))
+{
+    m_d->srcImage = srcImage;
+    m_d->srcImageOffset = srcImageOffset;
+}
+
 KisCageTransformWorker::~KisCageTransformWorker()
 {
 }
@@ -123,8 +146,10 @@ void KisCageTransformWorker::prepareTransform()
     if (m_d->origCage.size() < 3) return;
 
     const QPolygonF srcPolygon(m_d->origCage);
-    const QRect srcBounds = m_d->dev->region().boundingRect() &
-        srcPolygon.boundingRect().toAlignedRect();
+
+    QRect srcBounds = m_d->dev ? m_d->dev->region().boundingRect() :
+        QRectF(m_d->srcImageOffset, m_d->srcImage.size()).toAlignedRect();
+    srcBounds &= srcPolygon.boundingRect().toAlignedRect();
 
     m_d->gridSize =
         GridIterationTools::calcGridSize(srcBounds, m_d->pixelPrecision);
@@ -158,20 +183,61 @@ void KisCageTransformWorker::prepareTransform()
     m_d->cage.precalculateGreenCoordinates(m_d->origCage, m_d->validPoints);
 }
 
-void KisCageTransformWorker::run()
+QVector<QPointF> KisCageTransformWorker::Private::calculateTransformedPoints()
 {
-    KIS_ASSERT_RECOVER_RETURN(m_d->origCage.size() == m_d->transfCage.size());
-
-    m_d->cage.generateTransformedCageNormals(m_d->transfCage);
+    cage.generateTransformedCageNormals(transfCage);
 
-    const int numValidPoints = m_d->validPoints.size();
+    const int numValidPoints = validPoints.size();
     QVector<QPointF> transformedPoints(numValidPoints);
 
     for (int i = 0; i < numValidPoints; i++) {
-        transformedPoints[i] = m_d->cage.transformedPoint(i, m_d->transfCage);
+        transformedPoints[i] = cage.transformedPoint(i, transfCage);
     }
 
-    // here the cage is not needed anymore
+    return transformedPoints;
+}
+
+template <class PolygonOp>
+void KisCageTransformWorker::Private::
+iterateThroughGrid(PolygonOp polygonOp,
+                   const QVector<QPointF> &transformedPoints)
+{
+    QVector<int> polygonPoints(4);
+
+    for (int row = 0; row < gridSize.height() - 1; row++) {
+        for (int col = 0; col < gridSize.width() - 1; col++) {
+            polygonPoints[0] = allToValidPointsMap[col + row * gridSize.width()];
+            if (polygonPoints[0] < 0) continue;
+            polygonPoints[1] = allToValidPointsMap[col + 1 + row * \
gridSize.width()]; +            if (polygonPoints[1] < 0) continue;
+            polygonPoints[2] = allToValidPointsMap[col + 1 + (row + 1) * \
gridSize.width()]; +            if (polygonPoints[2] < 0) continue;
+            polygonPoints[3] = allToValidPointsMap[col + (row + 1) * \
gridSize.width()]; +            if (polygonPoints[3] < 0) continue;
+
+            QPolygonF srcPolygon;
+            QPolygonF dstPolygon;
+
+            for (int i = 0; i < 4; i++) {
+                const int index = polygonPoints[i];
+                srcPolygon << validPoints[index];
+                dstPolygon << transformedPoints[index];
+            }
+
+            //qDebug() << ppVar(col) << ppVar(row);
+            //qDebug() << ppVar(srcPolygon);
+            //qDebug() << ppVar(dstPolygon);
+
+            polygonOp(srcPolygon, dstPolygon);
+        }
+    }
+}
+
+void KisCageTransformWorker::run()
+{
+    KIS_ASSERT_RECOVER_RETURN(m_d->origCage.size() == m_d->transfCage.size());
+
+    QVector<QPointF> transformedPoints = m_d->calculateTransformedPoints();
 
     KisPaintDeviceSP srcDev = new KisPaintDevice(*m_d->dev.data());
 
@@ -190,34 +256,52 @@ void KisCageTransformWorker::run()
     }
 
     GridIterationTools::PaintDevicePolygonOp polygonOp(srcDev, m_d->dev);
+    m_d->iterateThroughGrid(polygonOp, transformedPoints);
+}
 
-    QVector<int> polygonPoints(4);
-
-    for (int row = 0; row < m_d->gridSize.height() - 1; row++) {
-        for (int col = 0; col < m_d->gridSize.width() - 1; col++) {
-            polygonPoints[0] = m_d->allToValidPointsMap[col + row * \
                m_d->gridSize.width()];
-            if (polygonPoints[0] < 0) continue;
-            polygonPoints[1] = m_d->allToValidPointsMap[col + 1 + row * \
                m_d->gridSize.width()];
-            if (polygonPoints[1] < 0) continue;
-            polygonPoints[2] = m_d->allToValidPointsMap[col + 1 + (row + 1) * \
                m_d->gridSize.width()];
-            if (polygonPoints[2] < 0) continue;
-            polygonPoints[3] = m_d->allToValidPointsMap[col + (row + 1) * \
                m_d->gridSize.width()];
-            if (polygonPoints[3] < 0) continue;
+QImage KisCageTransformWorker::runOnQImage(QPointF *newOffset)
+{
+    KIS_ASSERT_RECOVER(m_d->origCage.size() == m_d->transfCage.size()) {
+        return QImage();
+    }
 
-            QPolygonF srcPolygon;
-            QPolygonF dstPolygon;
+    KIS_ASSERT_RECOVER(!m_d->srcImage.isNull()) {
+        return QImage();
+    }
 
-            for (int i = 0; i < 4; i++) {
-                const int index = polygonPoints[i];
-                srcPolygon << m_d->validPoints[index];
-                dstPolygon << transformedPoints[index];
-            }
+    KIS_ASSERT_RECOVER(m_d->srcImage.format() == QImage::Format_ARGB32) {
+        return QImage();
+    }
 
-            //qDebug() << ppVar(col) << ppVar(row);
-            //qDebug() << ppVar(srcPolygon);
-            //qDebug() << ppVar(dstPolygon);
+    QVector<QPointF> transformedPoints = m_d->calculateTransformedPoints();
 
-            polygonOp(srcPolygon, dstPolygon);
-        }
+    QRectF dstBounds;
+    foreach (const QPointF &pt, transformedPoints) {
+        kisAccumulateBounds(pt, &dstBounds);
     }
+
+    const QRectF srcBounds(m_d->srcImageOffset, m_d->srcImage.size());
+    dstBounds |= srcBounds;
+
+    QPointF dstQImageOffset = dstBounds.topLeft();
+    *newOffset = dstQImageOffset;
+
+    QRect dstBoundsI = dstBounds.toAlignedRect();
+
+
+    QImage dstImage(dstBoundsI.size(), m_d->srcImage.format());
+    dstImage.fill(0);
+
+    QPainter gc(&dstImage);
+    gc.drawImage(-dstQImageOffset + m_d->srcImageOffset, m_d->srcImage);
+    gc.setBrush(Qt::black);
+    gc.setPen(Qt::black);
+    gc.setCompositionMode(QPainter::CompositionMode_Clear);
+    gc.drawPolygon(QPolygonF(m_d->origCage).translated(-dstQImageOffset));
+
+    GridIterationTools::QImagePolygonOp polygonOp(m_d->srcImage, dstImage, \
m_d->srcImageOffset, dstQImageOffset); +    m_d->iterateThroughGrid(polygonOp, \
transformedPoints); +
+    return dstImage;
 }
+
diff --git a/krita/image/kis_cage_transform_worker.h \
b/krita/image/kis_cage_transform_worker.h index 3de21fc..2097d1c 100644
--- a/krita/image/kis_cage_transform_worker.h
+++ b/krita/image/kis_cage_transform_worker.h
@@ -33,12 +33,20 @@ public:
                            KoUpdater *progress,
                            int pixelPrecision = 8);
 
+    KisCageTransformWorker(const QImage &srcImage,
+                           const QPointF &srcImageOffset,
+                           const QVector<QPointF> &origCage,
+                           KoUpdater *progress,
+                           int pixelPrecision = 8);
+
     ~KisCageTransformWorker();
 
     void prepareTransform();
     void setTransformedCage(const QVector<QPointF> &transformedCage);
     void run();
 
+    QImage runOnQImage(QPointF *newOffset);
+
 private:
     struct Private;
     const QScopedPointer<Private> m_d;
diff --git a/krita/image/kis_global.h b/krita/image/kis_global.h
index 7060919..0dc3aae 100644
--- a/krita/image/kis_global.h
+++ b/krita/image/kis_global.h
@@ -199,5 +199,25 @@ inline QRect kisEnsureInRect(QRect rc, const QRect &bounds)
     return rc;
 }
 
+template <class Point, class Rect>
+inline void kisAccumulateBounds(const Point &pt, Rect *bounds)
+{
+    if (pt.x() > bounds->right()) {
+        bounds->setRight(pt.x());
+    }
+
+    if (pt.x() < bounds->left()) {
+        bounds->setLeft(pt.x());
+    }
+
+    if (pt.y() > bounds->bottom()) {
+        bounds->setBottom(pt.y());
+    }
+
+    if (pt.y() < bounds->top()) {
+        bounds->setTop(pt.y());
+    }
+}
+
 #endif // KISGLOBAL_H_
 
diff --git a/krita/image/kis_grid_interpolation_tools.h \
b/krita/image/kis_grid_interpolation_tools.h index d781ae4..a9d4936 100644
--- a/krita/image/kis_grid_interpolation_tools.h
+++ b/krita/image/kis_grid_interpolation_tools.h
@@ -128,7 +128,7 @@ void processGrid(ProcessCell &cellOp,
             colIndex++;
 
             if (col > srcBounds.right() &&
-                col < srcBounds.right() + pixelPrecision - 1) {
+                col <= srcBounds.right() + pixelPrecision - 1) {
 
                 col = srcBounds.right();
             } else {
@@ -144,7 +144,7 @@ void processGrid(ProcessCell &cellOp,
         rowIndex++;
 
         if (row > srcBounds.bottom() &&
-            row < srcBounds.bottom() + pixelPrecision - 1) {
+            row <= srcBounds.bottom() + pixelPrecision - 1) {
 
             row = srcBounds.bottom();
         } else {
diff --git a/krita/image/kis_warptransform_worker.cc \
b/krita/image/kis_warptransform_worker.cc index 3051ead..af6f295 100644
--- a/krita/image/kis_warptransform_worker.cc
+++ b/krita/image/kis_warptransform_worker.cc
@@ -303,7 +303,7 @@ QImage KisWarpTransformWorker::transformQImage(WarpType warpType,
 
     FunctionTransformOp functionOp(warpMathFunction, origPoint, transfPoint, alpha);
 
-    const QRect srcBounds = srcImage.rect();
+    const QRectF srcBounds = QRectF(srcQImageOffset, srcImage.size());
     QRectF dstBounds;
 
     {
@@ -332,15 +332,15 @@ QImage KisWarpTransformWorker::transformQImage(WarpType \
warpType,  }
 
     QPointF dstQImageOffset = dstBounds.topLeft();
-    *newOffset = srcQImageOffset + dstQImageOffset;
+    *newOffset = dstQImageOffset;
 
     QRect dstBoundsI = dstBounds.toAlignedRect();
     QImage dstImage(dstBoundsI.size(), srcImage.format());
-    dstImage.fill(128);
+    dstImage.fill(0);
 
     const int pixelPrecision = 32;
-    GridIterationTools::QImagePolygonOp polygonOp(srcImage, dstImage, QPointF(), \
                dstQImageOffset);
-    GridIterationTools::processGrid(polygonOp, functionOp, srcBounds, \
pixelPrecision); +    GridIterationTools::QImagePolygonOp polygonOp(srcImage, \
dstImage, srcQImageOffset, dstQImageOffset); +    \
GridIterationTools::processGrid(polygonOp, functionOp, srcBounds.toAlignedRect(), \
pixelPrecision);  
     return dstImage;
 }
diff --git a/krita/image/tests/kis_cage_transform_worker_test.cpp \
b/krita/image/tests/kis_cage_transform_worker_test.cpp index 958e358..5d66b5c 100644
--- a/krita/image/tests/kis_cage_transform_worker_test.cpp
+++ b/krita/image/tests/kis_cage_transform_worker_test.cpp
@@ -27,7 +27,7 @@
 #include <kis_cage_transform_worker.h>
 #include <algorithm>
 
-void testCage(bool clockwise, bool unityTransform, bool benchmarkPrepareOnly = \
false, int pixelPrecision = 8) +void testCage(bool clockwise, bool unityTransform, \
bool benchmarkPrepareOnly = false, int pixelPrecision = 8, bool testQImage = false)  \
{  TestUtil::TestProgressBar bar;
     KoProgressUpdater pu(&bar);
@@ -77,23 +77,46 @@ void testCage(bool clockwise, bool unityTransform, bool \
benchmarkPrepareOnly = f  updater,
                                   pixelPrecision);
 
-    QBENCHMARK_ONCE {
-        worker.prepareTransform();
+    QImage result;
+    QPointF srcQImageOffset(0, 0);
+    QPointF dstQImageOffset;
 
-        if (!benchmarkPrepareOnly) {
-            worker.setTransformedCage(transfPoints);
-            worker.run();
+    QBENCHMARK_ONCE {
+        if (!testQImage) {
+            worker.prepareTransform();
+            if (!benchmarkPrepareOnly) {
+                worker.setTransformedCage(transfPoints);
+                worker.run();
+
+            }
+        } else {
+            QImage srcImage(image);
+            image = QImage(image.size(), QImage::Format_ARGB32);
+            QPainter gc(&image);
+            gc.drawImage(QPoint(), srcImage);
+
+            image.convertToFormat(QImage::Format_ARGB32);
+
+            KisCageTransformWorker qimageWorker(image,
+                                                srcQImageOffset,
+                                                origPoints,
+                                                updater,
+                                                pixelPrecision);
+            qimageWorker.prepareTransform();
+            qimageWorker.setTransformedCage(transfPoints);
+            result = qimageWorker.runOnQImage(&dstQImageOffset);
         }
     }
 
-    if (!benchmarkPrepareOnly && pixelPrecision == 8) {
-
-        QImage result = dev->convertToQImage(0);
+    QString testName = QString("%1_%2")
+        .arg(clockwise ? "clk" : "cclk")
+        .arg(unityTransform ? "unity" : "normal");
 
-        QString testName = QString("%1_%2")
-            .arg(clockwise ? "clk" : "cclk")
-            .arg(unityTransform ? "unity" : "normal");
+    if (testQImage) {
+        QVERIFY(TestUtil::checkQImage(result, "cage_transform_test", "cage_qimage", \
testName)); +    } else if (!benchmarkPrepareOnly && pixelPrecision == 8) {
 
+        result = dev->convertToQImage(0);
         QVERIFY(TestUtil::checkQImage(result, "cage_transform_test", "cage", \
testName));  }
 }
@@ -113,6 +136,11 @@ void \
KisCageTransformWorkerTest::testCageClockwisePixePrecision4()  testCage(true, false, \
false, 4);  }
 
+void KisCageTransformWorkerTest::testCageClockwisePixePrecision8QImage()
+{
+    testCage(true, false, false, 8, true);
+}
+
 void KisCageTransformWorkerTest::testCageCounterclockwise()
 {
     testCage(false, false);
diff --git a/krita/image/tests/kis_cage_transform_worker_test.h \
b/krita/image/tests/kis_cage_transform_worker_test.h index 11e5cfc..6c60855 100644
--- a/krita/image/tests/kis_cage_transform_worker_test.h
+++ b/krita/image/tests/kis_cage_transform_worker_test.h
@@ -28,6 +28,7 @@ private slots:
     void testCageClockwise();
     void testCageClockwisePrepareOnly();
     void testCageClockwisePixePrecision4();
+    void testCageClockwisePixePrecision8QImage();
     void testCageCounterclockwise();
     void testCageClockwiseUnity();
     void testCageCounterclockwiseUnity();
diff --git a/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp \
b/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp index \
                caa965f..97b6836 100644
--- a/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp
+++ b/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.cpp
@@ -23,6 +23,7 @@
 
 #include "krita_utils.h"
 #include "kis_cursor.h"
+#include <kis_cage_transform_worker.h>
 
 
 struct KisCageTransformStrategy::Private
@@ -76,3 +77,22 @@ void KisCageTransformStrategy::drawConnectionLines(QPainter &gc,
         gc.drawLine(transfPoints[prevIdx], transfPoints[idx]);
     }
 }
+
+QImage KisCageTransformStrategy::calculateTransformedImage(ToolTransformArgs \
&currentArgs, +                                                           const \
QImage &srcImage, +                                                           const \
QVector<QPointF> &origPoints, +                                                       \
const QVector<QPointF> &transfPoints, +                                               \
const QPointF &srcOffset, +                                                           \
QPointF *dstOffset) +{
+    Q_UNUSED(currentArgs);
+
+    KisCageTransformWorker worker(srcImage,
+                                  srcOffset,
+                                  origPoints,
+                                  0,
+                                  16);
+    worker.prepareTransform();
+    worker.setTransformedCage(transfPoints);
+    return worker.runOnQImage(dstOffset);
+}
diff --git a/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.h \
b/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.h index \
                e1cb98e..59b77ed 100644
--- a/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.h
+++ b/krita/plugins/tools/tool_transform2/kis_cage_transform_strategy.h
@@ -49,6 +49,13 @@ protected:
                              const QVector<QPointF> &transfPoints,
                              bool isEditingPoints);
 
+    QImage calculateTransformedImage(ToolTransformArgs &currentArgs,
+                                     const QImage &srcImage,
+                                     const QVector<QPointF> &origPoints,
+                                     const QVector<QPointF> &transfPoints,
+                                     const QPointF &srcOffset,
+                                     QPointF *dstOffset);
+
 private:
     class Private;
     const QScopedPointer<Private> m_d;
diff --git a/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp \
b/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp index \
                8fd0665..c27272b 100644
--- a/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp
+++ b/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.cpp
@@ -376,13 +376,12 @@ void \
KisWarpTransformStrategy::Private::recalculateTransformations()  
         }
 
-        transformedImage =
-            KisWarpTransformWorker::transformQImage(
-                currentArgs.warpType(),
-                thumbOrigPoints, thumbTransfPoints,
-                currentArgs.alpha(),
-                transformedImage,
-                origTLInFlake, &paintingOffset);
+        transformedImage = q->calculateTransformedImage(currentArgs,
+                                                        transformedImage,
+                                                        thumbOrigPoints,
+                                                        thumbTransfPoints,
+                                                        origTLInFlake,
+                                                        &paintingOffset);
     } else {
         transformedImage = q->originalImage();
         paintingOffset = imageToThumb(transaction.originalTopLeft(), false);
@@ -391,3 +390,18 @@ void \
KisWarpTransformStrategy::Private::recalculateTransformations()  
     handlesTransform = scaleTransform;
 }
+
+QImage KisWarpTransformStrategy::calculateTransformedImage(ToolTransformArgs \
&currentArgs, +                                                           const \
QImage &srcImage, +                                                           const \
QVector<QPointF> &origPoints, +                                                       \
const QVector<QPointF> &transfPoints, +                                               \
const QPointF &srcOffset, +                                                           \
QPointF *dstOffset) +{
+    return KisWarpTransformWorker::transformQImage(
+        currentArgs.warpType(),
+        origPoints, transfPoints,
+        currentArgs.alpha(),
+        srcImage,
+        srcOffset, dstOffset);
+}
diff --git a/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.h \
b/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.h index \
                bc0e690..655bea4 100644
--- a/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.h
+++ b/krita/plugins/tools/tool_transform2/kis_warp_transform_strategy.h
@@ -72,6 +72,13 @@ protected:
                                      const QVector<QPointF> &origPoints,
                                      const QVector<QPointF> &transfPoints,
                                      bool isEditingPoints);
+
+    virtual QImage calculateTransformedImage(ToolTransformArgs &currentArgs,
+                                             const QImage &srcImage,
+                                             const QVector<QPointF> &origPoints,
+                                             const QVector<QPointF> &transfPoints,
+                                             const QPointF &srcOffset,
+                                             QPointF *dstOffset);
 private:
     class Private;
     const QScopedPointer<Private> m_d;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic