[calligra/calligra/2.9] krita: [FEATURE] Make brush 'speed' sensor work

Dmitry Kazakov dimula73 at gmail.com
Mon Jun 22 13:27:51 UTC 2015


Git commit f3d76c6c37eb3be3a618eaf890a75586b4f2b9b4 by Dmitry Kazakov.
Committed on 22/06/2015 at 13:26.
Pushed by dkazakov into branch 'calligra/2.9'.

[FEATURE] Make brush 'speed' sensor work

Implemented a complex smoothing algorithm for speed sensor,
which makes Speed work almost perfectly.

The smoothing is two-stage:
1) Calculate the distance of the path connecting last 10 points
   (but not longer than 300px).
2) Divide the distance by time value and smooth the result further
   with 10 previous values

BUG:325423
Fixes:T426
CC:kimageshop at kde.org

M  +90   -37   krita/image/brushengine/kis_paint_information.cc
M  +19   -9    krita/image/brushengine/kis_paint_information.h
M  +1    -1    krita/image/tests/kis_paint_information_test.cpp
M  +1    -1    krita/libbrush/kis_auto_brush.cpp
M  +1    -1    krita/libbrush/tests/kis_auto_brush_test.cpp
M  +8    -8    krita/libbrush/tests/kis_brush_test.cpp
M  +3    -3    krita/libbrush/tests/kis_imagepipe_brush_test.cpp
M  +8    -8    krita/plugins/paintops/libpaintop/tests/kis_sensors_test.cpp
M  +1    -0    krita/ui/CMakeLists.txt
M  +28   -2    krita/ui/tool/kis_painting_information_builder.cpp
M  +6    -1    krita/ui/tool/kis_painting_information_builder.h
A  +120  -0    krita/ui/tool/kis_speed_smoother.cpp     [License: GPL (v2+)]
A  +40   -0    krita/ui/tool/kis_speed_smoother.h     [License: GPL (v2+)]
M  +1    -1    krita/ui/tool/kis_tool_freehand.cc

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

diff --git a/krita/image/brushengine/kis_paint_information.cc b/krita/image/brushengine/kis_paint_information.cc
index 2cda4fc..028a087 100644
--- a/krita/image/brushengine/kis_paint_information.cc
+++ b/krita/image/brushengine/kis_paint_information.cc
@@ -30,7 +30,32 @@
 struct KisPaintInformation::Private {
     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 
-    Private() : currentDistanceInfo(0) {}
+    Private(const QPointF & pos_,
+            qreal pressure_,
+            qreal xTilt_, qreal yTilt_,
+            qreal rotation_,
+            qreal tangentialPressure_,
+            qreal perspective_,
+            qreal time_,
+            qreal speed_,
+            bool isHoveringMode_)
+        :
+        pos(pos_),
+        pressure(pressure_),
+        xTilt(xTilt_),
+        yTilt(yTilt_),
+        rotation(rotation_),
+        tangentialPressure(tangentialPressure_),
+        perspective(perspective_),
+        time(time_),
+        speed(speed_),
+        isHoveringMode(isHoveringMode_),
+        currentDistanceInfo(0)
+    {
+    }
+
+
+
     ~Private() {
         KIS_ASSERT_RECOVER_NOOP(!currentDistanceInfo);
     }
@@ -51,6 +76,7 @@ struct KisPaintInformation::Private {
         tangentialPressure = rhs.tangentialPressure;
         perspective = rhs.perspective;
         time = rhs.time;
+        speed = rhs.speed;
         isHoveringMode = rhs.isHoveringMode;
         currentDistanceInfo = rhs.currentDistanceInfo;
 
@@ -68,6 +94,7 @@ struct KisPaintInformation::Private {
     qreal tangentialPressure;
     qreal perspective;
     qreal time;
+    qreal speed;
     bool isHoveringMode;
 
     QScopedPointer<qreal> drawingAngleOverride;
@@ -95,27 +122,60 @@ KisPaintInformation::DistanceInformationRegistrar::
     p->d->unregisterDistanceInfo();
 }
 
-KisPaintInformation::KisPaintInformation(const QPointF & pos_,
-        qreal pressure_,
-        qreal xTilt_, qreal yTilt_,
-        qreal rotation_,
-        qreal tangentialPressure_,
-        qreal perspective_,
-        qreal time)
-    : d(new Private)
+KisPaintInformation::KisPaintInformation(const QPointF & pos,
+                                         qreal pressure,
+                                         qreal xTilt, qreal yTilt,
+                                         qreal rotation,
+                                         qreal tangentialPressure,
+                                         qreal perspective,
+                                         qreal time,
+                                         qreal speed)
+    : d(new Private(pos,
+                    pressure,
+                    xTilt, yTilt,
+                    rotation,
+                    tangentialPressure,
+                    perspective,
+                    time,
+                    speed,
+                    false))
+{
+}
+
+KisPaintInformation::KisPaintInformation(const QPointF & pos,
+                                         qreal pressure,
+                                         qreal xTilt,
+                                         qreal yTilt,
+                                         qreal rotation)
+    : d(new Private(pos,
+                    pressure,
+                    xTilt, yTilt,
+                    rotation,
+                    0.0,
+                    1.0,
+                    0.0,
+                    0.0,
+                    false))
+{
+
+}
+
+KisPaintInformation::KisPaintInformation(const QPointF &pos,
+                                         qreal pressure)
+    : d(new Private(pos,
+                    pressure,
+                    0.0, 0.0,
+                    0.0,
+                    0.0,
+                    1.0,
+                    0.0,
+                    0.0,
+                    false))
 {
-    d->pos = pos_;
-    d->pressure = pressure_;
-    d->xTilt = xTilt_;
-    d->yTilt = yTilt_;
-    d->rotation = rotation_;
-    d->tangentialPressure = tangentialPressure_;
-    d->perspective = perspective_;
-    d->time = time;
-    d->isHoveringMode = false;
 }
 
-KisPaintInformation::KisPaintInformation(const KisPaintInformation& rhs) : d(new Private(*rhs.d))
+KisPaintInformation::KisPaintInformation(const KisPaintInformation& rhs)
+    : d(new Private(*rhs.d))
 {
 }
 
@@ -140,14 +200,15 @@ KisPaintInformation::createHoveringModeInfo(const QPointF &pos,
         qreal xTilt, qreal yTilt,
         qreal rotation,
         qreal tangentialPressure,
-        qreal perspective)
+        qreal perspective,
+        qreal speed)
 {
     KisPaintInformation info(pos,
                              pressure,
                              xTilt, yTilt,
                              rotation,
                              tangentialPressure,
-                             perspective, 0);
+                             perspective, 0, speed);
     info.d->isHoveringMode = true;
     return info;
 }
@@ -166,6 +227,7 @@ void KisPaintInformation::toXML(QDomDocument&, QDomElement& e) const
     e.setAttribute("tangentialPressure", QString::number(tangentialPressure(), 'g', 15));
     e.setAttribute("perspective", QString::number(perspective(), 'g', 15));
     e.setAttribute("time", d->time);
+    e.setAttribute("speed", d->speed);
 }
 
 KisPaintInformation KisPaintInformation::fromXML(const QDomElement& e)
@@ -179,9 +241,10 @@ KisPaintInformation KisPaintInformation::fromXML(const QDomElement& e)
     qreal xTilt = qreal(e.attribute("xTilt", "0.0").toDouble());
     qreal yTilt = qreal(e.attribute("yTilt", "0.0").toDouble());
     qreal time = e.attribute("time", "0").toDouble();
+    qreal speed = e.attribute("speed", "0").toDouble();
 
     return KisPaintInformation(QPointF(pointX, pointY), pressure, xTilt, yTilt,
-                               rotation, tangentialPressure, perspective, time);
+                               rotation, tangentialPressure, perspective, time, speed);
 }
 
 const QPointF& KisPaintInformation::pos() const
@@ -275,19 +338,7 @@ qreal KisPaintInformation::drawingDistance() const
 
 qreal KisPaintInformation::drawingSpeed() const
 {
-    if (!d->currentDistanceInfo || !d->currentDistanceInfo->hasLastDabInformation()) {
-        qWarning() << "KisPaintInformation::drawingSpeed()" << "Cannot access Distance Info last dab data";
-        return 0.5;
-    }
-
-    qreal timeDiff = currentTime() - d->currentDistanceInfo->lastTime();
-
-    if (timeDiff <= 0) {
-        return 0.5;
-    }
-
-    QVector2D diff(pos() - d->currentDistanceInfo->lastPosition());
-    return diff.length() / timeDiff;
+    return d->speed;
 }
 
 qreal KisPaintInformation::rotation() const
@@ -340,7 +391,8 @@ KisPaintInformation KisPaintInformation::mixOnlyPosition(qreal t, const KisPaint
                                basePi.rotation(),
                                basePi.tangentialPressure(),
                                basePi.perspective(),
-                               basePi.currentTime());
+                               basePi.currentTime(),
+                               basePi.drawingSpeed());
 
     return result;
 }
@@ -370,8 +422,9 @@ KisPaintInformation KisPaintInformation::mix(const QPointF& p, qreal t, const Ki
     qreal tangentialPressure = (1 - t) * pi1.tangentialPressure() + t * pi2.tangentialPressure();
     qreal perspective = (1 - t) * pi1.perspective() + t * pi2.perspective();
     qreal time = (1 - t) * pi1.currentTime() + t * pi2.currentTime();
+    qreal speed = (1 - t) * pi1.drawingSpeed() + t * pi2.drawingSpeed();
 
-    KisPaintInformation result(p, pressure, xTilt, yTilt, rotation, tangentialPressure, perspective, time);
+    KisPaintInformation result(p, pressure, xTilt, yTilt, rotation, tangentialPressure, perspective, time, speed);
     KIS_ASSERT_RECOVER_NOOP(pi1.isHoveringMode() == pi2.isHoveringMode());
     result.d->isHoveringMode = pi1.isHoveringMode();
 
diff --git a/krita/image/brushengine/kis_paint_information.h b/krita/image/brushengine/kis_paint_information.h
index 7ff84a1..decd7eb 100644
--- a/krita/image/brushengine/kis_paint_information.h
+++ b/krita/image/brushengine/kis_paint_information.h
@@ -75,16 +75,25 @@ public:
 
     /**
      * Create a new KisPaintInformation object.
-
      */
+    KisPaintInformation(const QPointF & pos,
+                        qreal pressure,
+                        qreal xTilt,
+                        qreal yTilt,
+                        qreal rotation,
+                        qreal tangentialPressure,
+                        qreal perspective,
+                        qreal time,
+                        qreal speed);
+
+    KisPaintInformation(const QPointF & pos,
+                        qreal pressure,
+                        qreal xTilt,
+                        qreal yTilt,
+                        qreal rotation);
+
     KisPaintInformation(const QPointF & pos = QPointF(),
-                        qreal pressure = PRESSURE_DEFAULT,
-                        qreal xTilt = 0.0,
-                        qreal yTilt = 0.0,
-                        qreal rotation = 0.0,
-                        qreal tangentialPressure = 0.0,
-                        qreal perspective = 1.0,
-                        qreal time = 0.0);
+                        qreal pressure = PRESSURE_DEFAULT);
 
     KisPaintInformation(const KisPaintInformation& rhs);
 
@@ -198,7 +207,8 @@ public:
             qreal xTilt = 0.0, qreal yTilt = 0.0,
             qreal rotation = 0.0,
             qreal tangentialPressure = 0.0,
-            qreal perspective = 1.0);
+            qreal perspective = 1.0,
+            qreal speed = 0.0);
 
     void toXML(QDomDocument&, QDomElement&) const;
 
diff --git a/krita/image/tests/kis_paint_information_test.cpp b/krita/image/tests/kis_paint_information_test.cpp
index 011e6d2..f842e91 100644
--- a/krita/image/tests/kis_paint_information_test.cpp
+++ b/krita/image/tests/kis_paint_information_test.cpp
@@ -34,7 +34,7 @@ void KisPaintInformationTest::testCreation()
 
 void KisPaintInformationTest::testSerialisation()
 {
-    KisPaintInformation test(QPointF(double(rand()) / RAND_MAX, double(rand()) / RAND_MAX), double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX);
+    KisPaintInformation test(QPointF(double(rand()) / RAND_MAX, double(rand()) / RAND_MAX), double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX);
 
     QDomDocument doc = QDomDocument("pi");
     QDomElement root = doc.createElement("pi");
diff --git a/krita/libbrush/kis_auto_brush.cpp b/krita/libbrush/kis_auto_brush.cpp
index eefaef8..86cc379 100644
--- a/krita/libbrush/kis_auto_brush.cpp
+++ b/krita/libbrush/kis_auto_brush.cpp
@@ -294,7 +294,7 @@ QImage KisAutoBrush::createBrushPreview()
     int width = maskWidth(1.0, 0.0, 0.0, 0.0, KisPaintInformation());
     int height = maskHeight(1.0, 0.0, 0.0, 0.0, KisPaintInformation());
 
-    KisPaintInformation info(QPointF(width * 0.5, height * 0.5), 0.5, 0, angle(), 0, 0);
+    KisPaintInformation info(QPointF(width * 0.5, height * 0.5), 0.5, 0, 0, angle(), 0, 0, 0, 0);
 
     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(KoColorSpaceRegistry::instance()->rgb8());
     fdev->setRect(QRect(0, 0, width, height));
diff --git a/krita/libbrush/tests/kis_auto_brush_test.cpp b/krita/libbrush/tests/kis_auto_brush_test.cpp
index 7a7767a..1a447d5 100644
--- a/krita/libbrush/tests/kis_auto_brush_test.cpp
+++ b/krita/libbrush/tests/kis_auto_brush_test.cpp
@@ -44,7 +44,7 @@ void KisAutoBrushTest::testMaskGeneration()
     KisBrushSP a = new KisAutoBrush(circle, 0.0, 0.0);
     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
 
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
 
     // check masking an existing paint device
     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
diff --git a/krita/libbrush/tests/kis_brush_test.cpp b/krita/libbrush/tests/kis_brush_test.cpp
index a9b38bf..3ca422f 100644
--- a/krita/libbrush/tests/kis_brush_test.cpp
+++ b/krita/libbrush/tests/kis_brush_test.cpp
@@ -39,7 +39,7 @@ void KisBrushTest::testMaskGenerationNoColor()
     Q_ASSERT(brush->valid());
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
 
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
 
     // check masking an existing paint device
     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
@@ -73,7 +73,7 @@ void KisBrushTest::testMaskGenerationSingleColor()
     Q_ASSERT(brush->valid());
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
 
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
 
     // check masking an existing paint device
     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
@@ -101,7 +101,7 @@ void KisBrushTest::testMaskGenerationDevColor()
     Q_ASSERT(brush->valid());
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
 
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
 
     // check masking an existing paint device
     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
@@ -134,7 +134,7 @@ void KisBrushTest::testMaskGenerationDefaultColor()
     Q_ASSERT(brush->valid());
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
 
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
 
     // check masking an existing paint device
     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
@@ -169,7 +169,7 @@ void KisBrushTest::testImageGeneration()
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
     KisFixedPaintDeviceSP dab;
 
     for (int i = 0; i < 200; i++) {
@@ -213,7 +213,7 @@ void KisBrushTest::benchmarkScaling()
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
     KisFixedPaintDeviceSP dab;
 
     QBENCHMARK {
@@ -231,7 +231,7 @@ void KisBrushTest::benchmarkRotation()
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
     KisFixedPaintDeviceSP dab;
 
     QBENCHMARK {
@@ -248,7 +248,7 @@ void KisBrushTest::benchmarkMaskScaling()
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, 0, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
     KisFixedPaintDeviceSP dab = new KisFixedPaintDevice(cs);
 
     QBENCHMARK {
diff --git a/krita/libbrush/tests/kis_imagepipe_brush_test.cpp b/krita/libbrush/tests/kis_imagepipe_brush_test.cpp
index cf69126..94187e0 100644
--- a/krita/libbrush/tests/kis_imagepipe_brush_test.cpp
+++ b/krita/libbrush/tests/kis_imagepipe_brush_test.cpp
@@ -110,7 +110,7 @@ void KisImagePipeBrushTest::testChangingBrushes()
     QVERIFY(brush->valid());
 
     qreal rotation = 0;
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation);
 
     for (int i = 0; i < 100; i++) {
         checkConsistency(brush);
@@ -133,7 +133,7 @@ void checkIncrementalPainting(KisBrush *brush, const QString &prefix)
     qreal rotation = 0;
     qreal subPixelX = 0.0;
     qreal subPixelY = 0.0;
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation);
 
     for (int i = 0; i < 20; i++) {
         int maskWidth = brush->maskWidth(realScale, realAngle, subPixelX, subPixelY, info);
@@ -210,7 +210,7 @@ void KisImagePipeBrushTest::testColoredDabWash()
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
 
     qreal rotation = 0;
-    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation, 0);
+    KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation);
 
     KisPaintDeviceSP layer = new KisPaintDevice(cs);
     KisPainter painter(layer);
diff --git a/krita/plugins/paintops/libpaintop/tests/kis_sensors_test.cpp b/krita/plugins/paintops/libpaintop/tests/kis_sensors_test.cpp
index 4f6dc27..1b68d20 100644
--- a/krita/plugins/paintops/libpaintop/tests/kis_sensors_test.cpp
+++ b/krita/plugins/paintops/libpaintop/tests/kis_sensors_test.cpp
@@ -23,14 +23,14 @@
 
 KisSensorsTest::KisSensorsTest()
 {
-    paintInformations.append(KisPaintInformation(QPointF(0, 0), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(0, 1), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(1, 2), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(2, 2), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(3, 1), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(3, 0), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(2, -1), 0, 0, 0, 0.0, 0.0, 1.0));
-    paintInformations.append(KisPaintInformation(QPointF(1, -1), 0, 0, 0, 0.0, 0.0, 1.0));
+    paintInformations.append(KisPaintInformation(QPointF(0, 0)));
+    paintInformations.append(KisPaintInformation(QPointF(0, 1)));
+    paintInformations.append(KisPaintInformation(QPointF(1, 2)));
+    paintInformations.append(KisPaintInformation(QPointF(2, 2)));
+    paintInformations.append(KisPaintInformation(QPointF(3, 1)));
+    paintInformations.append(KisPaintInformation(QPointF(3, 0)));
+    paintInformations.append(KisPaintInformation(QPointF(2, -1)));
+    paintInformations.append(KisPaintInformation(QPointF(1, -1)));
 }
 
 void KisSensorsTest::testDrawingAngle()
diff --git a/krita/ui/CMakeLists.txt b/krita/ui/CMakeLists.txt
index 4588a7e..f1dfdb1 100644
--- a/krita/ui/CMakeLists.txt
+++ b/krita/ui/CMakeLists.txt
@@ -170,6 +170,7 @@ set(kritaui_LIB_SRCS
     tool/kis_tool.cc
     tool/kis_delegated_tool_policies.cpp
     tool/kis_tool_freehand.cc
+    tool/kis_speed_smoother.cpp
     tool/kis_painting_information_builder.cpp
     tool/kis_tool_freehand_helper.cpp
     tool/kis_tool_multihand_helper.cpp
diff --git a/krita/ui/tool/kis_painting_information_builder.cpp b/krita/ui/tool/kis_painting_information_builder.cpp
index d9fe055..b2ce828 100644
--- a/krita/ui/tool/kis_painting_information_builder.cpp
+++ b/krita/ui/tool/kis_painting_information_builder.cpp
@@ -24,6 +24,7 @@
 #include "kis_config_notifier.h"
 
 #include "kis_cubic_curve.h"
+#include "kis_speed_smoother.h"
 
 
 /***********************************************************************/
@@ -35,6 +36,7 @@ const int KisPaintingInformationBuilder::LEVEL_OF_PRESSURE_RESOLUTION = 1024;
 
 
 KisPaintingInformationBuilder::KisPaintingInformationBuilder()
+    : m_speedSmoother(new KisSpeedSmoother())
 {
     connect(KisConfigNotifier::instance(), SIGNAL(configChanged()),
             SLOT(updateSettings()));
@@ -42,6 +44,11 @@ KisPaintingInformationBuilder::KisPaintingInformationBuilder()
     updateSettings();
 }
 
+KisPaintingInformationBuilder::~KisPaintingInformationBuilder()
+{
+
+}
+
 void KisPaintingInformationBuilder::updateSettings()
 {
     KisConfig cfg;
@@ -74,6 +81,11 @@ QPointF KisPaintingInformationBuilder::documentToImage(const QPointF &point)
     return point;
 }
 
+QPointF KisPaintingInformationBuilder::imageToView(const QPointF &point)
+{
+    return point;
+}
+
 qreal KisPaintingInformationBuilder::calculatePerspective(const QPointF &documentPoint)
 {
     Q_UNUSED(documentPoint);
@@ -88,6 +100,7 @@ KisPaintInformation KisPaintingInformationBuilder::createPaintingInformation(KoP
     QPointF adjusted = adjustDocumentPoint(event->point, m_startPoint);
     QPointF imagePoint = documentToImage(adjusted);
     qreal perspective = calculatePerspective(adjusted);
+    qreal speed = m_speedSmoother->getNextSpeed(imageToView(imagePoint));
 
     return KisPaintInformation(imagePoint,
                                pressureToCurve(event->pressure()),
@@ -95,13 +108,15 @@ KisPaintInformation KisPaintingInformationBuilder::createPaintingInformation(KoP
                                event->rotation(),
                                event->tangentialPressure(),
                                perspective,
-                               timeElapsed);
+                               timeElapsed,
+                               speed);
 }
 
 KisPaintInformation KisPaintingInformationBuilder::hover(const QPointF &imagePoint,
                                                          const KoPointerEvent *event)
 {
     qreal perspective = calculatePerspective(imagePoint);
+    qreal speed = m_speedSmoother->getNextSpeed(imageToView(imagePoint));
 
     if (event) {
         return KisPaintInformation::createHoveringModeInfo(imagePoint,
@@ -109,7 +124,8 @@ KisPaintInformation KisPaintingInformationBuilder::hover(const QPointF &imagePoi
                                                            event->xTilt(), event->yTilt(),
                                                            event->rotation(),
                                                            event->tangentialPressure(),
-                                                           perspective);
+                                                           perspective,
+                                                           speed);
     } else {
         return KisPaintInformation::createHoveringModeInfo(imagePoint);
     }
@@ -136,6 +152,11 @@ QPointF KisConverterPaintingInformationBuilder::documentToImage(const QPointF &p
     return m_converter->documentToImage(point);
 }
 
+QPointF KisConverterPaintingInformationBuilder::imageToView(const QPointF &point)
+{
+    return m_converter->documentToWidget(point);
+}
+
 /***********************************************************************/
 /*           KisToolFreehandPaintingInformationBuilder                        */
 /***********************************************************************/
@@ -152,6 +173,11 @@ QPointF KisToolFreehandPaintingInformationBuilder::documentToImage(const QPointF
     return m_tool->convertToPixelCoord(point);
 }
 
+QPointF KisToolFreehandPaintingInformationBuilder::imageToView(const QPointF &point)
+{
+    return m_tool->pixelToView(point);
+}
+
 QPointF KisToolFreehandPaintingInformationBuilder::adjustDocumentPoint(const QPointF &point, const QPointF &startPoint)
 {
     return m_tool->adjustPosition(point, startPoint);
diff --git a/krita/ui/tool/kis_painting_information_builder.h b/krita/ui/tool/kis_painting_information_builder.h
index d1970bc..02db87c 100644
--- a/krita/ui/tool/kis_painting_information_builder.h
+++ b/krita/ui/tool/kis_painting_information_builder.h
@@ -30,7 +30,7 @@ class KoPointerEvent;
 class KisTool;
 class KisToolFreehand;
 class KisCoordinatesConverter;
-
+class KisSpeedSmoother;
 
 class KRITAUI_EXPORT KisPaintingInformationBuilder : public QObject
 {
@@ -38,6 +38,7 @@ class KRITAUI_EXPORT KisPaintingInformationBuilder : public QObject
 
 public:
     KisPaintingInformationBuilder();
+    ~KisPaintingInformationBuilder();
 
     KisPaintInformation startStroke(KoPointerEvent *event, int timeElapsed);
 
@@ -53,6 +54,7 @@ protected Q_SLOTS:
 protected:
     virtual QPointF adjustDocumentPoint(const QPointF &point, const QPointF &startPoint);
     virtual QPointF documentToImage(const QPointF &point);
+    virtual QPointF imageToView(const QPointF &point);
     virtual qreal calculatePerspective(const QPointF &documentPoint);
 
 private:
@@ -70,6 +72,7 @@ private:
 private:
     QVector<qreal> m_pressureSamples;
     QPointF m_startPoint;
+    QScopedPointer<KisSpeedSmoother> m_speedSmoother;
 };
 
 class KRITAUI_EXPORT KisConverterPaintingInformationBuilder : public KisPaintingInformationBuilder
@@ -81,6 +84,7 @@ public:
 
 protected:
     virtual QPointF documentToImage(const QPointF &point);
+    virtual QPointF imageToView(const QPointF &point);
 
 private:
     const KisCoordinatesConverter *m_converter;
@@ -95,6 +99,7 @@ public:
 
 protected:
     virtual QPointF documentToImage(const QPointF &point);
+    virtual QPointF imageToView(const QPointF &point);
     virtual QPointF adjustDocumentPoint(const QPointF &point, const QPointF &startPoint);
     virtual qreal calculatePerspective(const QPointF &documentPoint);
 
diff --git a/krita/ui/tool/kis_speed_smoother.cpp b/krita/ui/tool/kis_speed_smoother.cpp
new file mode 100644
index 0000000..b34b1fd
--- /dev/null
+++ b/krita/ui/tool/kis_speed_smoother.cpp
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_speed_smoother.h"
+
+#include <boost/circular_buffer.hpp>
+#include <QElapsedTimer>
+#include <QPointF>
+
+#include "kis_debug.h"
+#include "kis_global.h"
+
+#define MAX_SMOOTH_HISTORY 10
+#define MAX_TIME_DIFF 500
+#define MAX_TRACKING_DISTANCE 300
+#define MIN_TRACKING_DISTANCE 5
+
+
+struct KisSpeedSmoother::Private
+{
+    Private(int historySize)
+        : distances(historySize),
+          lastSpeed(0)
+    {
+        timer.start();
+    }
+
+    struct DistancePoint {
+        DistancePoint()
+            : distance(0), time(0)
+        {
+        }
+
+        DistancePoint(qreal _distance, qreal _time)
+            : distance(_distance), time(_time)
+        {
+        }
+
+        qreal distance;
+        qreal time;
+    };
+
+    typedef boost::circular_buffer<DistancePoint> DistanceBuffer;
+    DistanceBuffer distances;
+
+    QPointF lastPoint;
+    QElapsedTimer timer;
+    qreal lastSpeed;
+};
+
+
+KisSpeedSmoother::KisSpeedSmoother()
+    : m_d(new Private(MAX_SMOOTH_HISTORY))
+{
+}
+
+KisSpeedSmoother::~KisSpeedSmoother()
+{
+}
+
+qreal KisSpeedSmoother::getNextSpeed(const QPointF &pt)
+{
+    if (m_d->lastPoint.isNull()) {
+        m_d->lastPoint = pt;
+        return 0.0;
+    }
+
+    qreal time = qreal(m_d->timer.nsecsElapsed()) / 1000000;
+    qreal dist = kisDistance(pt, m_d->lastPoint);
+    m_d->lastPoint = pt;
+
+    m_d->distances.push_back(Private::DistancePoint(dist, time));
+
+    Private::DistanceBuffer::const_reverse_iterator it = m_d->distances.rbegin();
+    Private::DistanceBuffer::const_reverse_iterator end = m_d->distances.rend();
+
+    const qreal currentTime = it->time;
+
+    qreal totalDistance = 0;
+    qreal startTime = currentTime;
+
+    for (; it != end; ++it) {
+        if (currentTime - it->time > MAX_TIME_DIFF) {
+            break;
+        }
+
+        totalDistance += it->distance;
+        startTime = it->time;
+
+        if (totalDistance > MAX_TRACKING_DISTANCE) {
+            break;
+        }
+    }
+
+    qreal totalTime = currentTime - startTime;
+
+    if (totalTime > 0 && totalDistance > MIN_TRACKING_DISTANCE) {
+        qreal speed = totalDistance / totalTime;
+
+        const qreal alpha = 0.2;
+        m_d->lastSpeed = alpha * speed + (1 - alpha) * m_d->lastSpeed;
+    }
+
+    return m_d->lastSpeed;
+}
diff --git a/krita/ui/tool/kis_speed_smoother.h b/krita/ui/tool/kis_speed_smoother.h
new file mode 100644
index 0000000..3f40e7e
--- /dev/null
+++ b/krita/ui/tool/kis_speed_smoother.h
@@ -0,0 +1,40 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KIS_SPEED_SMOOTHER_H
+#define __KIS_SPEED_SMOOTHER_H
+
+#include <QScopedPointer>
+
+class QPointF;
+
+
+class KisSpeedSmoother
+{
+public:
+    KisSpeedSmoother();
+    ~KisSpeedSmoother();
+
+    qreal getNextSpeed(const QPointF &pt);
+
+private:
+    struct Private;
+    const QScopedPointer<Private> m_d;
+};
+
+#endif /* __KIS_SPEED_SMOOTHER_H */
diff --git a/krita/ui/tool/kis_tool_freehand.cc b/krita/ui/tool/kis_tool_freehand.cc
index 7b2bacf..bb2eec0 100644
--- a/krita/ui/tool/kis_tool_freehand.cc
+++ b/krita/ui/tool/kis_tool_freehand.cc
@@ -257,7 +257,7 @@ bool KisToolFreehand::tryPickByPaintOp(KoPointerEvent *event, AlternateAction ac
                                             event->xTilt(), event->yTilt(),
                                             event->rotation(),
                                             event->tangentialPressure(),
-                                            perspective, 0),
+                                            perspective, 0, 0),
                         event->modifiers());
     return !paintOpIgnoredEvent;
 }


More information about the kimageshop mailing list