[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [calligra] krita: Implement line smoothing in Krita
From: Boudewijn Rempt <boud () valdyas ! org>
Date: 2012-12-31 16:30:20
Message-ID: 20121231163020.8F489A6091 () git ! kde ! org
[Download RAW message or body]
Git commit f9cbf6a1bd864be88059255aa9c4b5b35208085d by Boudewijn Rempt.
Committed on 31/12/2012 at 17:04.
Pushed by rempt into branch 'master'.
Implement line smoothing in Krita
REVIEW:108049
BUG:281267
M +1 -1 krita/image/brushengine/kis_paint_information.h
M +17 -3 krita/image/kis_distance_information.h
M +5 -3 krita/plugins/paintops/libpaintop/sensors/kis_dynamic_sensors.cc
M +54 -18 krita/plugins/tools/defaulttools/kis_tool_brush.cc
M +8 -3 krita/plugins/tools/defaulttools/kis_tool_brush.h
M +1 -0 krita/ui/CMakeLists.txt
C +8 -17 krita/ui/tool/kis_smoothing_options.cpp [from: \
krita/image/kis_distance_information.h - 057% similarity] C +20 -14 \
krita/ui/tool/kis_smoothing_options.h [from: krita/image/kis_distance_information.h - \
057% similarity] M +1 -8 krita/ui/tool/kis_tool_freehand.cc
M +3 -3 krita/ui/tool/kis_tool_freehand.h
M +111 -31 krita/ui/tool/kis_tool_freehand_helper.cpp
M +7 -3 krita/ui/tool/kis_tool_freehand_helper.h
http://commits.kde.org/calligra/f9cbf6a1bd864be88059255aa9c4b5b35208085d
diff --git a/krita/image/brushengine/kis_paint_information.h \
b/krita/image/brushengine/kis_paint_information.h index 0142a33..8e1de78 100644
--- a/krita/image/brushengine/kis_paint_information.h
+++ b/krita/image/brushengine/kis_paint_information.h
@@ -111,7 +111,7 @@ public:
/// Number of ms since the beginning of the stroke
int currentTime() const;
-
+
void toXML(QDomDocument&, QDomElement&) const;
static KisPaintInformation fromXML(const QDomElement&);
diff --git a/krita/image/kis_distance_information.h \
b/krita/image/kis_distance_information.h index c1ab409..f2bd080 100644
--- a/krita/image/kis_distance_information.h
+++ b/krita/image/kis_distance_information.h
@@ -24,9 +24,23 @@
* to be passed for the next call.
*/
struct KisDistanceInformation {
- KisDistanceInformation() : distance(0), spacing(0) {}
- KisDistanceInformation(double _distance, double _spacing) : distance(_distance), \
spacing(_spacing) {}
- void clear() { distance = 0; spacing = 0;}
+
+ KisDistanceInformation()
+ : distance(0)
+ , spacing(0)
+ {}
+
+ KisDistanceInformation(double _distance, double _spacing)
+ : distance(_distance)
+ , spacing(_spacing)
+ {}
+
+ void clear()
+ {
+ distance = 0;
+ spacing = 0;
+ }
+
double distance;
double spacing;
};
diff --git a/krita/plugins/paintops/libpaintop/sensors/kis_dynamic_sensors.cc \
b/krita/plugins/paintops/libpaintop/sensors/kis_dynamic_sensors.cc index \
16473f5..c1aa015 100644
--- a/krita/plugins/paintops/libpaintop/sensors/kis_dynamic_sensors.cc
+++ b/krita/plugins/paintops/libpaintop/sensors/kis_dynamic_sensors.cc
@@ -30,10 +30,12 @@ KisDynamicSensorSpeed::KisDynamicSensorSpeed() : \
KisDynamicSensor(SpeedId) }
qreal KisDynamicSensorSpeed::value(const KisPaintInformation& info) {
- int dt = qMax(1, info.currentTime() - m_lastTime); // make sure dt > 1
+ int deltaTime = qMax(1, info.currentTime() - m_lastTime); // make sure deltaTime \
> 1 m_lastTime = info.currentTime();
- double currentMove = info.movement().norm() / dt;
- m_speed = qMin(1.0, (m_speed * 0.9 + currentMove * 0.1)); // average it to get \
nicer result, at the price of being less mathematically correct, but we quicly reach \
a situation where dt = 1 and currentMove = 1 + double currentMove = \
info.movement().norm() / deltaTime; + // Average it to get nicer result, at the \
price of being less mathematically correct, + // but we quickly reach a situation \
where dt = 1 and currentMove = 1 + m_speed = qMin(1.0, (m_speed * 0.9 + \
currentMove * 0.1)); return m_speed;
}
diff --git a/krita/plugins/tools/defaulttools/kis_tool_brush.cc \
b/krita/plugins/tools/defaulttools/kis_tool_brush.cc index 536b81d..3b6491b 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_brush.cc
+++ b/krita/plugins/tools/defaulttools/kis_tool_brush.cc
@@ -21,19 +21,22 @@
#include "kis_tool_brush.h"
#include <QCheckBox>
+#include <QComboBox>
#include <klocale.h>
#include "kis_cursor.h"
#include "kis_slider_spin_box.h"
-
-#define MAXIMUM_SMOOTHNESS 1000
+#define MAXIMUM_SMOOTHNESS_QUALITY 100 // 0..100
+#define MAXIMUM_SMOOTHNESS_FACTOR 1000.0 // 0..1000.0 == weight in gui
#define MAXIMUM_MAGNETISM 1000
KisToolBrush::KisToolBrush(KoCanvasBase * canvas)
- : KisToolFreehand(canvas, KisCursor::load("tool_freehand_cursor.png", 5, 5), \
i18nc("(qtundo-format)", "Brush")) + : KisToolFreehand(canvas,
+ KisCursor::load("tool_freehand_cursor.png", 5, 5),
+ i18nc("(qtundo-format)", "Brush"))
{
setObjectName("tool_brush");
}
@@ -42,9 +45,35 @@ KisToolBrush::~KisToolBrush()
{
}
-void KisToolBrush::slotSetSmoothness(int smoothness)
+void KisToolBrush::slotSetSmoothingType(int index)
{
- m_smoothness = smoothness / (double)MAXIMUM_SMOOTHNESS;
+ switch (index) {
+ case 0:
+ m_smoothingOptions.smoothingType = KisSmoothingOptions::NO_SMOOTHING;
+ m_sliderSmoothnessFactor->setEnabled(false);
+ m_sliderSmoothnessQuality->setEnabled(false);
+ break;
+ case 1:
+ m_smoothingOptions.smoothingType = KisSmoothingOptions::SIMPLE_SMOOTHING;
+ m_sliderSmoothnessFactor->setEnabled(false);
+ m_sliderSmoothnessQuality->setEnabled(false);
+ break;
+ case 2:
+ default:
+ m_smoothingOptions.smoothingType = KisSmoothingOptions::WEIGHTED_SMOOTHING;
+ m_sliderSmoothnessFactor->setEnabled(true);
+ m_sliderSmoothnessQuality->setEnabled(true);
+ }
+}
+
+void KisToolBrush::slotSetSmoothnessQuality(int quality)
+{
+ m_smoothingOptions.smoothnessQuality = quality;
+}
+
+void KisToolBrush::slotSetSmoothnessFactor(qreal factor)
+{
+ m_smoothingOptions.smoothnessFactor = factor;
}
void KisToolBrush::slotSetMagnetism(int magnetism)
@@ -54,23 +83,30 @@ void KisToolBrush::slotSetMagnetism(int magnetism)
QWidget * KisToolBrush::createOptionWidget()
{
-
QWidget * optionWidget = KisToolFreehand::createOptionWidget();
optionWidget->setObjectName(toolId() + "option widget");
- m_chkSmooth = new QCheckBox(i18nc("smooth out the curves while drawing", \
"Smoothness:"), optionWidget);
- m_chkSmooth->setObjectName("chkSmooth");
- m_chkSmooth->setChecked(m_smooth);
- connect(m_chkSmooth, SIGNAL(toggled(bool)), this, SLOT(setSmooth(bool)));
+ // Line smoothing configuration
+ m_cmbSmoothingType = new QComboBox(optionWidget);
+ m_cmbSmoothingType->addItems(QStringList() << i18n("No Smoothing") << \
i18n("Basic Smoothing") << i18n("Weighted Smoothing")); + \
m_cmbSmoothingType->setCurrentIndex(2); + connect(m_cmbSmoothingType, \
SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetSmoothingType(int))); + \
addOptionWidgetOption(m_cmbSmoothingType); +
+ m_sliderSmoothnessQuality = new KisSliderSpinBox(optionWidget);
+ m_sliderSmoothnessQuality->setRange(1, MAXIMUM_SMOOTHNESS_QUALITY);
+ m_sliderSmoothnessQuality->setEnabled(true);
+ connect(m_sliderSmoothnessQuality, SIGNAL(valueChanged(int)), \
SLOT(slotSetSmoothnessQuality(int))); + \
m_sliderSmoothnessQuality->setValue(m_smoothingOptions.smoothnessQuality); + \
addOptionWidgetOption(m_sliderSmoothnessQuality, new QLabel(i18n("Quality:")));
- m_sliderSmoothness = new KisSliderSpinBox(optionWidget);
- m_sliderSmoothness->setRange(0, MAXIMUM_SMOOTHNESS);
- m_sliderSmoothness->setEnabled(true);
- connect(m_chkSmooth, SIGNAL(toggled(bool)), m_sliderSmoothness, \
SLOT(setEnabled(bool)));
- connect(m_sliderSmoothness, SIGNAL(valueChanged(int)), \
SLOT(slotSetSmoothness(int)));
- m_sliderSmoothness->setValue(m_smoothness * MAXIMUM_SMOOTHNESS);
+ m_sliderSmoothnessFactor = new KisDoubleSliderSpinBox(optionWidget);
+ m_sliderSmoothnessFactor->setRange(3.0, MAXIMUM_SMOOTHNESS_FACTOR, 1);
+ m_sliderSmoothnessFactor->setEnabled(true);
+ connect(m_sliderSmoothnessFactor, SIGNAL(valueChanged(qreal)), \
SLOT(slotSetSmoothnessFactor(qreal))); + \
m_sliderSmoothnessFactor->setValue(m_smoothingOptions.smoothnessFactor);
- addOptionWidgetOption(m_sliderSmoothness, m_chkSmooth);
+ addOptionWidgetOption(m_sliderSmoothnessFactor, new QLabel(i18n("Weight:")));
// Drawing assistant configuration
m_chkAssistant = new QCheckBox(i18n("Assistant:"), optionWidget);
@@ -78,7 +114,7 @@ QWidget * KisToolBrush::createOptionWidget()
connect(m_chkAssistant, SIGNAL(toggled(bool)), this, SLOT(setAssistant(bool)));
m_sliderMagnetism = new KisSliderSpinBox(optionWidget);
m_sliderMagnetism->setToolTip(i18n("Assistant Magnetism"));
- m_sliderMagnetism->setRange(0, MAXIMUM_SMOOTHNESS);
+ m_sliderMagnetism->setRange(0, MAXIMUM_MAGNETISM);
m_sliderMagnetism->setEnabled(false);
connect(m_chkAssistant, SIGNAL(toggled(bool)), m_sliderMagnetism, \
SLOT(setEnabled(bool))); m_sliderMagnetism->setValue(m_magnetism * \
MAXIMUM_MAGNETISM);
diff --git a/krita/plugins/tools/defaulttools/kis_tool_brush.h \
b/krita/plugins/tools/defaulttools/kis_tool_brush.h index f849233..dbf5c37 100644
--- a/krita/plugins/tools/defaulttools/kis_tool_brush.h
+++ b/krita/plugins/tools/defaulttools/kis_tool_brush.h
@@ -32,6 +32,7 @@ class QGridLayout;
class KoCanvasBase;
class KisSliderSpinBox;
+class KisDoubleSliderSpinBox;
class KisToolBrush : public KisToolFreehand
{
@@ -44,15 +45,19 @@ public:
QWidget * createOptionWidget();
private slots:
- void slotSetSmoothness(int smoothness);
+ void slotSetSmoothnessQuality(int quality);
+ void slotSetSmoothnessFactor(qreal factor);
void slotSetMagnetism(int magnetism);
+ void slotSetSmoothingType(int index);
private:
QGridLayout *m_optionLayout;
- QCheckBox *m_chkSmooth;
+ QComboBox *m_cmbSmoothingType;
+
QCheckBox *m_chkAssistant;
KisSliderSpinBox *m_sliderMagnetism;
- KisSliderSpinBox *m_sliderSmoothness;
+ KisDoubleSliderSpinBox *m_sliderSmoothnessFactor;
+ KisSliderSpinBox *m_sliderSmoothnessQuality;
};
diff --git a/krita/ui/CMakeLists.txt b/krita/ui/CMakeLists.txt
index 2d8abc4..3eebb0a 100644
--- a/krita/ui/CMakeLists.txt
+++ b/krita/ui/CMakeLists.txt
@@ -147,6 +147,7 @@ set(kritaui_LIB_SRCS
tool/kis_tool_polyline_base.cpp
tool/kis_color_picker_utils.cpp
tool/kis_resources_snapshot.cpp
+ tool/kis_smoothing_options.cpp
tool/strokes/freehand_stroke.cpp
tool/strokes/kis_painter_based_stroke_strategy.cpp
widgets/kis_channelflags_widget.cpp
diff --git a/krita/image/kis_distance_information.h \
b/krita/ui/tool/kis_smoothing_options.cpp similarity index 57%
copy from krita/image/kis_distance_information.h
copy to krita/ui/tool/kis_smoothing_options.cpp
index c1ab409..14326c4 100644
--- a/krita/image/kis_distance_information.h
+++ b/krita/ui/tool/kis_smoothing_options.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Cyrille Berger <cberger@cberger.net>
+ * Copyright (c) 2012 Boudewijn Rempt <boud@valdyas.org>
*
* 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
@@ -15,20 +15,11 @@
* 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_smoothing_options.h"
-#ifndef _KIS_DISTANCE_INFORMATION_H_
-#define _KIS_DISTANCE_INFORMATION_H_
-
-/**
- * This function is used as return of paintLine to contains information that need
- * to be passed for the next call.
- */
-struct KisDistanceInformation {
- KisDistanceInformation() : distance(0), spacing(0) {}
- KisDistanceInformation(double _distance, double _spacing) : distance(_distance), \
spacing(_spacing) {}
- void clear() { distance = 0; spacing = 0;}
- double distance;
- double spacing;
-};
-
-#endif
+KisSmoothingOptions::KisSmoothingOptions()
+ : smoothingType(WEIGHTED_SMOOTHING)
+ , smoothnessFactor(50.0)
+ , smoothnessQuality(20)
+{
+}
diff --git a/krita/image/kis_distance_information.h \
b/krita/ui/tool/kis_smoothing_options.h similarity index 57%
copy from krita/image/kis_distance_information.h
copy to krita/ui/tool/kis_smoothing_options.h
index c1ab409..b28144d 100644
--- a/krita/image/kis_distance_information.h
+++ b/krita/ui/tool/kis_smoothing_options.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Cyrille Berger <cberger@cberger.net>
+ * Copyright (c) 2012 Boudewijn Rempt <boud@valdyas.org>
*
* 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
@@ -15,20 +15,26 @@
* 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_SMOOTHING_OPTIONS_H
+#define KIS_SMOOTHING_OPTIONS_H
-#ifndef _KIS_DISTANCE_INFORMATION_H_
-#define _KIS_DISTANCE_INFORMATION_H_
+#include <qglobal.h>
+
+struct KisSmoothingOptions
+{
+
+ enum SmoothingType {
+ NO_SMOOTHING = 0,
+ SIMPLE_SMOOTHING,
+ WEIGHTED_SMOOTHING
+ };
+
+ KisSmoothingOptions();
+
+ SmoothingType smoothingType;
+ qreal smoothnessFactor;
+ int smoothnessQuality;
-/**
- * This function is used as return of paintLine to contains information that need
- * to be passed for the next call.
- */
-struct KisDistanceInformation {
- KisDistanceInformation() : distance(0), spacing(0) {}
- KisDistanceInformation(double _distance, double _spacing) : distance(_distance), \
spacing(_spacing) {}
- void clear() { distance = 0; spacing = 0;}
- double distance;
- double spacing;
};
-#endif
+#endif // KIS_SMOOTHING_OPTIONS_H
diff --git a/krita/ui/tool/kis_tool_freehand.cc b/krita/ui/tool/kis_tool_freehand.cc
index 5640a4b..87595aa 100644
--- a/krita/ui/tool/kis_tool_freehand.cc
+++ b/krita/ui/tool/kis_tool_freehand.cc
@@ -71,9 +71,7 @@ KisToolFreehand::KisToolFreehand(KoCanvasBase * canvas, const \
QCursor & cursor, {
m_explicitShowOutline = false;
- m_smooth = true;
m_assistant = false;
- m_smoothness = 1.0;
m_magnetism = 1.0;
setSupportOutline(true);
@@ -160,7 +158,7 @@ void KisToolFreehand::initStroke(KoPointerEvent *event)
{
setCurrentNodeLocked(true);
- m_helper->setSmoothness(m_smooth, m_smoothness);
+ m_helper->setSmoothness(m_smoothingOptions);
m_helper->initPaint(event, canvas()->resourceManager(),
image(),
image().data(),
@@ -336,11 +334,6 @@ bool KisToolFreehand::wantsAutoScroll() const
return false;
}
-void KisToolFreehand::setSmooth(bool smooth)
-{
- m_smooth = smooth;
-}
-
void KisToolFreehand::setAssistant(bool assistant)
{
m_assistant = assistant;
diff --git a/krita/ui/tool/kis_tool_freehand.h b/krita/ui/tool/kis_tool_freehand.h
index ee915d8..adc8445 100644
--- a/krita/ui/tool/kis_tool_freehand.h
+++ b/krita/ui/tool/kis_tool_freehand.h
@@ -25,6 +25,7 @@
#include "kis_resources_snapshot.h"
#include "kis_paintop_settings.h"
#include "kis_distance_information.h"
+#include "kis_smoothing_options.h"
#include "krita_export.h"
@@ -83,7 +84,6 @@ protected:
protected slots:
- void setSmooth(bool smooth);
void setAssistant(bool assistant);
private:
@@ -114,8 +114,8 @@ private slots:
void hideOutline();
protected:
- bool m_smooth;
- double m_smoothness;
+
+ KisSmoothingOptions m_smoothingOptions;
bool m_assistant;
double m_magnetism;
diff --git a/krita/ui/tool/kis_tool_freehand_helper.cpp \
b/krita/ui/tool/kis_tool_freehand_helper.cpp index dde51ea..0d63072 100644
--- a/krita/ui/tool/kis_tool_freehand_helper.cpp
+++ b/krita/ui/tool/kis_tool_freehand_helper.cpp
@@ -30,7 +30,10 @@
#include "kis_recording_adapter.h"
#include "kis_image.h"
#include "kis_painter.h"
+#include "kis_smoothing_options.h"
+#include <math.h>
+#include <qnumeric.h> // for qIsNaN
struct KisToolFreehandHelper::Private
{
@@ -41,7 +44,6 @@ struct KisToolFreehandHelper::Private
bool haveTangent;
QPointF previousTangent;
-
bool hasPaintAtLeastOnce;
QTime strokeTime;
@@ -54,10 +56,12 @@ struct KisToolFreehandHelper::Private
KisPaintInformation previousPaintInformation;
KisPaintInformation olderPaintInformation;
- bool smooth;
- qreal smoothness;
+ KisSmoothingOptions smoothingOptions;
QTimer airbrushingTimer;
+
+ QList<KisPaintInformation> history;
+ QList<qreal> velocityHistory;
};
@@ -68,9 +72,6 @@ KisToolFreehandHelper::KisToolFreehandHelper(KisPaintingInformationBuilder \
*info m_d->infoBuilder = infoBuilder;
m_d->recordingAdapter = recordingAdapter;
- m_d->smooth = true;
- m_d->smoothness = 1.0;
-
m_d->strokeTimeoutTimer.setSingleShot(true);
connect(&m_d->strokeTimeoutTimer, SIGNAL(timeout()), SLOT(finishStroke()));
@@ -82,10 +83,9 @@ KisToolFreehandHelper::~KisToolFreehandHelper()
delete m_d;
}
-void KisToolFreehandHelper::setSmoothness(bool smooth, qreal smoothness)
+void KisToolFreehandHelper::setSmoothness(const KisSmoothingOptions \
&smoothingOptions) {
- m_d->smooth = smooth;
- m_d->smoothness = smoothness;
+ m_d->smoothingOptions = smoothingOptions;
}
void KisToolFreehandHelper::initPaint(KoPointerEvent *event,
@@ -99,7 +99,6 @@ void KisToolFreehandHelper::initPaint(KoPointerEvent *event,
m_d->strokesFacade = strokesFacade;
-
m_d->haveTangent = false;
m_d->previousTangent = QPointF();
@@ -123,14 +122,18 @@ void KisToolFreehandHelper::initPaint(KoPointerEvent *event,
}
KisStrokeStrategy *stroke =
- new FreehandStrokeStrategy(indirectPainting,
- m_d->resources, m_d->painterInfos, i18n("Freehand \
Stroke")); + new FreehandStrokeStrategy(indirectPainting,
+ m_d->resources, m_d->painterInfos, \
i18n("Freehand Stroke"));
m_d->strokeId = m_d->strokesFacade->startStroke(stroke);
m_d->previousPaintInformation =
- m_d->infoBuilder->startStroke(event, m_d->strokeTime.elapsed());
+ m_d->infoBuilder->startStroke(event, m_d->strokeTime.elapsed());
+ m_d->history.clear();
+ m_d->history.append(m_d->previousPaintInformation);
+ m_d->velocityHistory.clear();
+ m_d->velocityHistory.append(std::numeric_limits<qreal>::signaling_NaN());
if(m_d->resources->needsAirbrushing()) {
m_d->airbrushingTimer.setInterval(m_d->resources->airbrushingRate());
m_d->airbrushingTimer.start();
@@ -140,19 +143,93 @@ void KisToolFreehandHelper::initPaint(KoPointerEvent *event,
void KisToolFreehandHelper::paint(KoPointerEvent *event)
{
KisPaintInformation info =
- m_d->infoBuilder->continueStroke(event,
- m_d->previousPaintInformation.pos(),
- m_d->strokeTime.elapsed());
+ m_d->infoBuilder->continueStroke(event,
+ m_d->previousPaintInformation.pos(),
+ m_d->strokeTime.elapsed());
+
+ // Smooth the coordinates out using the history and the velocity. See
+ // https://bugs.kde.org/show_bug.cgi?id=281267 and \
http://www24.atwiki.jp/sigetch_2007/pages/17.html. + // This is also implemented \
in gimp, which is where I cribbed the code from. + if \
(m_d->smoothingOptions.smoothingType == KisSmoothingOptions::WEIGHTED_SMOOTHING + \
&& m_d->smoothingOptions.smoothnessQuality > 1 + && \
m_d->smoothingOptions.smoothnessFactor > 3.0) { +
+ m_d->history.append(info);
+ m_d->velocityHistory.append(std::numeric_limits<qreal>::signaling_NaN()); // \
Fake velocity! +
+ qreal x = 0.0;
+ qreal y = 0.0;
+
+ if (m_d->history.size() > 3) {
+
+ int length = qMin(m_d->smoothingOptions.smoothnessQuality, \
m_d->history.size()); + int minIndex = m_d->history.size() - length;
+
+ qreal gaussianWeight = 0.0;
+ qreal gaussianWeight2 = m_d->smoothingOptions.smoothnessFactor * \
m_d->smoothingOptions.smoothnessFactor; + qreal velocitySum = 0.0;
+ qreal scaleSum = 0.0;
+
+ if (gaussianWeight2 != 0.0) {
+ gaussianWeight = 1 / (sqrt(2 * M_PI) * \
m_d->smoothingOptions.smoothnessFactor); + }
+
+ Q_ASSERT(m_d->history.size() == m_d->velocityHistory.size());
+
+ for (int i = m_d->history.size() - 1; i >= minIndex; i--) {
+ qreal rate = 0.0;
+
+ const KisPaintInformation nextInfo = m_d->history.at(i);
+ double velocity = m_d->velocityHistory.at(i);
+
+ if (qIsNaN(velocity)) {
+
+ int previousTime = nextInfo.currentTime();
+ if (i > 0) {
+ previousTime = m_d->history.at(i - 1).currentTime();
+ }
+
+ int deltaTime = qMax(1, nextInfo.currentTime() - previousTime); \
// make sure deltaTime > 1 + velocity = info.movement().norm() / \
deltaTime; + m_d->velocityHistory[i] = velocity;
+ }
+
+ if (gaussianWeight2 != 0.0) {
+ velocitySum += velocity * 100;
+ rate = gaussianWeight * exp(-velocitySum * velocitySum / (2 * \
gaussianWeight2)); + }
+ scaleSum += rate;
+ x += rate * nextInfo.pos().x();
+ y += rate * nextInfo.pos().y();
+ }
+
+ if (scaleSum != 0.0) {
+ x /= scaleSum;
+ y /= scaleSum;
+ }
+ if ((x != 0.0 && y != 0.0) || (x == info.pos().x() && y == \
info.pos().y())) { + m_d->history.last().setPos(QPointF(x, y));
+ info.setPos(QPointF(x, y));
+ }
+ }
+ }
- if (m_d->smooth) {
+ if (m_d->smoothingOptions.smoothingType == KisSmoothingOptions::SIMPLE_SMOOTHING
+ || m_d->smoothingOptions.smoothingType == \
KisSmoothingOptions::WEIGHTED_SMOOTHING) + {
+ // Now paint between the coordinates, using the bezier curve interpolation
if (!m_d->haveTangent) {
m_d->haveTangent = true;
+
+ // XXX: 3.0 is a magic number I don't know anything about
+ // 1.0 was the old default value for smoothness, and anything lower \
than that + // gave horrible results, so remove that setting.
m_d->previousTangent =
- (info.pos() - m_d->previousPaintInformation.pos()) * m_d->smoothness \
/
- (3.0 * (info.currentTime() - \
m_d->previousPaintInformation.currentTime())); + (info.pos() - \
m_d->previousPaintInformation.pos()) / + (3.0 * \
(info.currentTime() - m_d->previousPaintInformation.currentTime())); } else {
- QPointF newTangent = (info.pos() - m_d->olderPaintInformation.pos()) * \
m_d->smoothness /
- (3.0 * (info.currentTime() - \
m_d->olderPaintInformation.currentTime())); + QPointF newTangent = \
(info.pos() - m_d->olderPaintInformation.pos()) / + (3.0 * \
(info.currentTime() - m_d->olderPaintInformation.currentTime()));
qreal scaleFactor = (m_d->previousPaintInformation.currentTime() - \
m_d->olderPaintInformation.currentTime());
QPointF control1 = m_d->olderPaintInformation.pos() + \
m_d->previousTangent * scaleFactor;
QPointF control2 = m_d->previousPaintInformation.pos() - newTangent * \
scaleFactor; @@ -165,10 +242,13 @@ void KisToolFreehandHelper::paint(KoPointerEvent \
*event) }
m_d->olderPaintInformation = m_d->previousPaintInformation;
m_d->strokeTimeoutTimer.start(100);
- } else {
+ }
+ else {
paintLine(m_d->painterInfos, m_d->previousPaintInformation, info);
}
+
+
m_d->previousPaintInformation = info;
if(m_d->airbrushingTimer.isActive()) {
@@ -180,7 +260,7 @@ void KisToolFreehandHelper::endPaint()
{
if (!m_d->hasPaintAtLeastOnce) {
paintAt(m_d->painterInfos, m_d->previousPaintInformation);
- } else if (m_d->smooth) {
+ } else if (m_d->smoothingOptions.smoothingType != \
KisSmoothingOptions::NO_SMOOTHING) { finishStroke();
}
m_d->strokeTimeoutTimer.stop();
@@ -215,7 +295,7 @@ void KisToolFreehandHelper::finishStroke()
if(m_d->haveTangent) {
m_d->haveTangent = false;
- QPointF newTangent = (m_d->previousPaintInformation.pos() - \
m_d->olderPaintInformation.pos()) * m_d->smoothness / 3.0; + QPointF \
newTangent = (m_d->previousPaintInformation.pos() - m_d->olderPaintInformation.pos()) \
/ 3.0;
qreal scaleFactor = (m_d->previousPaintInformation.currentTime() - \
m_d->olderPaintInformation.currentTime());
QPointF control1 = m_d->olderPaintInformation.pos() + m_d->previousTangent * \
scaleFactor;
QPointF control2 = m_d->previousPaintInformation.pos() - newTangent;
@@ -239,8 +319,8 @@ void KisToolFreehandHelper::paintAt(PainterInfo *painterInfo,
{
m_d->hasPaintAtLeastOnce = true;
m_d->strokesFacade->addJob(m_d->strokeId,
- new FreehandStrokeStrategy::Data(m_d->resources->currentNode(),
- painterInfo, pi));
+ new \
FreehandStrokeStrategy::Data(m_d->resources->currentNode(), + \
painterInfo, pi));
if(m_d->recordingAdapter) {
m_d->recordingAdapter->addPoint(pi);
@@ -253,8 +333,8 @@ void KisToolFreehandHelper::paintLine(PainterInfo *painterInfo,
{
m_d->hasPaintAtLeastOnce = true;
m_d->strokesFacade->addJob(m_d->strokeId,
- new FreehandStrokeStrategy::Data(m_d->resources->currentNode(),
- painterInfo, pi1, pi2));
+ new \
FreehandStrokeStrategy::Data(m_d->resources->currentNode(), + \
painterInfo, pi1, pi2));
if(m_d->recordingAdapter) {
m_d->recordingAdapter->addLine(pi1, pi2);
@@ -269,9 +349,9 @@ void KisToolFreehandHelper::paintBezierCurve(PainterInfo \
*painterInfo, {
m_d->hasPaintAtLeastOnce = true;
m_d->strokesFacade->addJob(m_d->strokeId,
- new FreehandStrokeStrategy::Data(m_d->resources->currentNode(),
- painterInfo,
- pi1, control1, control2, pi2));
+ new \
FreehandStrokeStrategy::Data(m_d->resources->currentNode(), + \
painterInfo, + pi1, \
control1, control2, pi2));
if(m_d->recordingAdapter) {
m_d->recordingAdapter->addCurve(pi1, control1, control2, pi2);
diff --git a/krita/ui/tool/kis_tool_freehand_helper.h \
b/krita/ui/tool/kis_tool_freehand_helper.h index 4978c85..ebfd526 100644
--- a/krita/ui/tool/kis_tool_freehand_helper.h
+++ b/krita/ui/tool/kis_tool_freehand_helper.h
@@ -35,21 +35,23 @@ class KisStrokesFacade;
class KisPostExecutionUndoAdapter;
class KisPaintOp;
class KisPainter;
-
+class KisSmoothingOptions;
class KRITAUI_EXPORT KisToolFreehandHelper : public QObject
{
Q_OBJECT
protected:
+
typedef FreehandStrokeStrategy::PainterInfo PainterInfo;
public:
+
KisToolFreehandHelper(KisPaintingInformationBuilder *infoBuilder,
KisRecordingAdapter *recordingAdapter = 0);
~KisToolFreehandHelper();
- void setSmoothness(bool smooth, qreal smoothness);
+ void setSmoothness(const KisSmoothingOptions &smoothingOptions);
void initPaint(KoPointerEvent *event,
KoCanvasResourceManager *resourceManager,
@@ -63,6 +65,7 @@ public:
const KisPaintOp* currentPaintOp() const;
protected:
+
virtual void createPainters(QVector<PainterInfo*> &painterInfos);
virtual void paintAt(const QVector<PainterInfo*> &painterInfos,
@@ -78,7 +81,7 @@ protected:
const QPointF &control2,
const KisPaintInformation &pi2);
-protected:
+
void paintAt(PainterInfo *painterInfo, const KisPaintInformation &pi);
void paintLine(PainterInfo *painterInfo,
@@ -92,6 +95,7 @@ protected:
const KisPaintInformation &pi2);
private slots:
+
void finishStroke();
void doAirbrushing();
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic