[krita] libs: FEATURE: auto-smoothing for bezier curve tools
Dmitry Kazakov
null at kde.org
Thu Aug 23 16:52:46 BST 2018
Git commit 58444e98e7a230c50dcc27f6705d6e2da919e63d by Dmitry Kazakov.
Committed on 23/08/2018 at 15:52.
Pushed by dkazakov into branch 'master'.
FEATURE: auto-smoothing for bezier curve tools
Now if you select auto-smoothing the cerated curve will
be not a "polygon", but a smooth curve with the type of all the
points set to "smooth".
BUG:351787
CC:kimageshop at kde.org
M +48 -0 libs/basicflakes/tools/KoCreatePathTool.cpp
M +4 -0 libs/basicflakes/tools/KoCreatePathTool.h
M +17 -0 libs/basicflakes/tools/KoCreatePathTool_p.h
M +25 -16 libs/flake/commands/KoPathPointTypeCommand.cpp
M +2 -0 libs/flake/commands/KoPathPointTypeCommand.h
M +10 -0 libs/ui/kis_config.cc
M +3 -0 libs/ui/kis_config.h
https://commits.kde.org/krita/58444e98e7a230c50dcc27f6705d6e2da919e63d
diff --git a/libs/basicflakes/tools/KoCreatePathTool.cpp b/libs/basicflakes/tools/KoCreatePathTool.cpp
index c2063193bb2..fa54cfdd5e0 100644
--- a/libs/basicflakes/tools/KoCreatePathTool.cpp
+++ b/libs/basicflakes/tools/KoCreatePathTool.cpp
@@ -34,6 +34,7 @@
#include <KoColor.h>
#include "kis_canvas_resource_provider.h"
#include <KisHandlePainterHelper.h>
+#include "KoPathPointTypeCommand.h"
#include <klocalizedstring.h>
@@ -290,6 +291,38 @@ void KoCreatePathTool::mouseMoveEvent(KoPointerEvent *event)
}
} else {
d->activePoint->setPoint(snappedPosition);
+
+ if (!d->prevPointWasDragged && d->autoSmoothCurves) {
+ KoPathPointIndex index = d->shape->pathPointIndex(d->activePoint);
+ if (index.second > 0) {
+
+ KoPathPointIndex prevIndex(index.first, index.second - 1);
+ KoPathPoint *prevPoint = d->shape->pointByIndex(prevIndex);
+
+ if (prevPoint) {
+ KoPathPoint *prevPrevPoint = 0;
+
+ if (index.second > 1) {
+ KoPathPointIndex prevPrevIndex(index.first, index.second - 2);
+ prevPrevPoint = d->shape->pointByIndex(prevPrevIndex);
+ }
+
+ if (prevPrevPoint) {
+ const QPointF control1 = prevPoint->point() + 0.3 * (prevPrevPoint->point() - prevPoint->point());
+ prevPoint->setControlPoint1(control1);
+ }
+
+ const QPointF control2 = prevPoint->point() + 0.3 * (d->activePoint->point() - prevPoint->point());
+ prevPoint->setControlPoint2(control2);
+
+ const QPointF activeControl = d->activePoint->point() + 0.3 * (prevPoint->point() - d->activePoint->point());
+ d->activePoint->setControlPoint1(activeControl);
+
+ KoPathPointTypeCommand::makeCubicPointSmooth(prevPoint);
+ }
+ }
+ }
+
}
canvas()->updateCanvas(d->shape->boundingRect());
@@ -304,6 +337,7 @@ void KoCreatePathTool::mouseReleaseEvent(KoPointerEvent *event)
d->listeningToModifiers = true; // After the first press-and-release
d->repaintActivePoint();
+ d->prevPointWasDragged = d->pointIsDragged;
d->pointIsDragged = false;
KoPathPoint *lastActivePoint = d->activePoint;
@@ -325,6 +359,11 @@ void KoCreatePathTool::mouseReleaseEvent(KoPointerEvent *event)
d->firstPoint->setControlPoint1(d->activePoint->controlPoint1());
delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
d->activePoint = d->firstPoint;
+
+ if (!d->prevPointWasDragged && d->autoSmoothCurves) {
+ KoPathPointTypeCommand::makeCubicPointSmooth(d->activePoint);
+ }
+
d->shape->closeMerge();
// we are closing the path, so reset the existing start path point
@@ -408,6 +447,7 @@ void KoCreatePathTool::activate(ToolActivation activation, const QSet<KoShape*>
// retrieve the actual global handle radius
d->handleRadius = handleRadius();
+ d->loadAutoSmoothValueFromConfig();
// reset snap guide
canvas()->updateCanvas(canvas()->snapGuide()->boundingRect());
@@ -502,6 +542,14 @@ QList<QPointer<QWidget> > KoCreatePathTool::createOptionWidgets()
QList<QPointer<QWidget> > list;
+ QCheckBox *smoothCurves = new QCheckBox(i18n("Autosmooth curve"));
+ smoothCurves->setObjectName("smooth-curves-widget");
+ smoothCurves->setChecked(d->autoSmoothCurves);
+ connect(smoothCurves, SIGNAL(toggled(bool)), this, SLOT(autoSmoothCurvesChanged(bool)));
+ connect(this, SIGNAL(sigUpdateAutoSmoothCurvesGUI(bool)), smoothCurves, SLOT(setChecked(bool)));
+
+ list.append(smoothCurves);
+
QWidget *angleWidget = new QWidget();
angleWidget->setObjectName("Angle Constraints");
QGridLayout *layout = new QGridLayout(angleWidget);
diff --git a/libs/basicflakes/tools/KoCreatePathTool.h b/libs/basicflakes/tools/KoCreatePathTool.h
index 3924e354f1b..a1c5a437e96 100644
--- a/libs/basicflakes/tools/KoCreatePathTool.h
+++ b/libs/basicflakes/tools/KoCreatePathTool.h
@@ -81,6 +81,9 @@ public Q_SLOTS:
/// reimplemented
void documentResourceChanged(int key, const QVariant & res) override;
+Q_SIGNALS:
+ void sigUpdateAutoSmoothCurvesGUI(bool value);
+
protected:
/**
* Add path shape to document.
@@ -109,5 +112,6 @@ private:
Q_DECLARE_PRIVATE(KoCreatePathTool)
Q_PRIVATE_SLOT(d_func(), void angleDeltaChanged(int))
Q_PRIVATE_SLOT(d_func(), void angleSnapChanged(int))
+ Q_PRIVATE_SLOT(d_func(), void autoSmoothCurvesChanged(bool))
};
#endif
diff --git a/libs/basicflakes/tools/KoCreatePathTool_p.h b/libs/basicflakes/tools/KoCreatePathTool_p.h
index 2f68d9f4794..c6b863a56c1 100644
--- a/libs/basicflakes/tools/KoCreatePathTool_p.h
+++ b/libs/basicflakes/tools/KoCreatePathTool_p.h
@@ -31,6 +31,7 @@
#include "KoSnapStrategy.h"
#include "KoToolBase_p.h"
#include <KoViewConverter.h>
+#include "kis_config.h"
#include "math.h"
@@ -205,6 +206,8 @@ public:
PathConnectionPoint existingEndPoint; ///< an existing path point we finished a new path at
KoPathPoint *hoveredPoint; ///< an existing path end point the mouse is hovering on
bool listeningToModifiers; // Fine tune when to begin processing modifiers at the beginning of a stroke.
+ bool prevPointWasDragged = false;
+ bool autoSmoothCurves = false;
QPointF dragStartPoint;
@@ -415,6 +418,20 @@ public:
angleSnapStrategy->setAngleStep(angleSnappingDelta);
}
+ void autoSmoothCurvesChanged(bool value) {
+ autoSmoothCurves = value;
+
+ KisConfig cfg(false);
+ cfg.setAutoSmoothBezierCurves(value);
+ }
+
+ void loadAutoSmoothValueFromConfig() {
+ KisConfig cfg(true);
+ autoSmoothCurves = cfg.autoSmoothBezierCurves();
+
+ emit q->sigUpdateAutoSmoothCurvesGUI(autoSmoothCurves);
+ }
+
void angleSnapChanged(int angleSnap) {
angleSnapStatus = ! angleSnapStatus;
if (angleSnapStrategy) {
diff --git a/libs/flake/commands/KoPathPointTypeCommand.cpp b/libs/flake/commands/KoPathPointTypeCommand.cpp
index d61ac53e7b5..b87215a7e68 100644
--- a/libs/flake/commands/KoPathPointTypeCommand.cpp
+++ b/libs/flake/commands/KoPathPointTypeCommand.cpp
@@ -106,6 +106,7 @@ void KoPathPointTypeCommand::redo()
} else
point->setControlPoint2(cubic.first()->controlPoint2());
}
+ point->setProperties(properties);
break;
}
case Symmetric: {
@@ -126,33 +127,20 @@ void KoPathPointTypeCommand::redo()
// the new distance of the control points is the average distance to the node point
point->setControlPoint1(point->point() + 0.5 * averageLength * (directionC1 - directionC2));
point->setControlPoint2(point->point() + 0.5 * averageLength * (directionC2 - directionC1));
+ point->setProperties(properties);
}
break;
case Smooth: {
- properties &= ~KoPathPoint::IsSymmetric;
- properties |= KoPathPoint::IsSmooth;
-
- // calculate vector from node point to first control point and normalize it
- QPointF directionC1 = point->controlPoint1() - point->point();
- qreal dirLengthC1 = sqrt(directionC1.x() * directionC1.x() + directionC1.y() * directionC1.y());
- directionC1 /= dirLengthC1;
- // calculate vector from node point to second control point and normalize it
- QPointF directionC2 = point->controlPoint2() - point->point();
- qreal dirLengthC2 = sqrt(directionC2.x() * directionC2.x() + directionC2.y() * directionC2.y());
- directionC2 /= dirLengthC2;
- // compute position of the control points so that they lie on a line going through the node point
- // the new distance of the control points is the average distance to the node point
- point->setControlPoint1(point->point() + 0.5 * dirLengthC1 * (directionC1 - directionC2));
- point->setControlPoint2(point->point() + 0.5 * dirLengthC2 * (directionC2 - directionC1));
+ makeCubicPointSmooth(point);
}
break;
case Corner:
default:
properties &= ~KoPathPoint::IsSymmetric;
properties &= ~KoPathPoint::IsSmooth;
+ point->setProperties(properties);
break;
}
- point->setProperties(properties);
}
repaint(true);
}
@@ -186,6 +174,27 @@ void KoPathPointTypeCommand::undo()
repaint(true);
}
+void KoPathPointTypeCommand::makeCubicPointSmooth(KoPathPoint *point)
+{
+ KoPathPoint::PointProperties properties = point->properties();
+
+ properties &= ~KoPathPoint::IsSymmetric;
+ properties |= KoPathPoint::IsSmooth;
+
+ // calculate vector from node point to first control point and normalize it
+ QPointF directionC1 = point->controlPoint1() - point->point();
+ qreal dirLengthC1 = sqrt(directionC1.x() * directionC1.x() + directionC1.y() * directionC1.y());
+ directionC1 /= dirLengthC1;
+ // calculate vector from node point to second control point and normalize it
+ QPointF directionC2 = point->controlPoint2() - point->point();
+ qreal dirLengthC2 = sqrt(directionC2.x() * directionC2.x() + directionC2.y() * directionC2.y());
+ directionC2 /= dirLengthC2;
+ // compute position of the control points so that they lie on a line going through the node point
+ // the new distance of the control points is the average distance to the node point
+ point->setControlPoint1(point->point() + 0.5 * dirLengthC1 * (directionC1 - directionC2));
+ point->setControlPoint2(point->point() + 0.5 * dirLengthC2 * (directionC2 - directionC1));
+}
+
void KoPathPointTypeCommand::undoChanges(const QList<PointData> &data)
{
QList<PointData>::const_iterator it(data.begin());
diff --git a/libs/flake/commands/KoPathPointTypeCommand.h b/libs/flake/commands/KoPathPointTypeCommand.h
index 849ec8b8040..f025a2314f8 100644
--- a/libs/flake/commands/KoPathPointTypeCommand.h
+++ b/libs/flake/commands/KoPathPointTypeCommand.h
@@ -54,6 +54,8 @@ public:
/// revert the actions done in redo
void undo() override;
+ static void makeCubicPointSmooth(KoPathPoint *point);
+
private:
// used for storing the data for undo
struct PointData {
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
index 9b224e836e7..f0cafa11754 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1965,6 +1965,16 @@ void KisConfig::setDefaultAssistantsColor(const QColor &color) const
m_cfg.writeEntry("defaultAssistantsColor", color);
}
+bool KisConfig::autoSmoothBezierCurves(bool defaultValue) const
+{
+ return defaultValue ? false : m_cfg.readEntry("autoSmoothBezierCurves", false);
+}
+
+void KisConfig::setAutoSmoothBezierCurves(bool value)
+{
+ m_cfg.writeEntry("autoSmoothBezierCurves", value);
+}
+
#include <QDomDocument>
#include <QDomElement>
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
index a8f04c75e26..c0d24bef74f 100644
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -566,6 +566,9 @@ public:
QColor defaultAssistantsColor(bool defaultValue = false) const;
void setDefaultAssistantsColor(const QColor &color) const;
+ bool autoSmoothBezierCurves(bool defaultValue = false) const;
+ void setAutoSmoothBezierCurves(bool value);
+
template<class T>
void writeEntry(const QString& name, const T& value) {
m_cfg.writeEntry(name, value);
More information about the kimageshop
mailing list