[krita/krita/4.1] libs: FEATURE: auto-smoothing for bezier curve tools

Boudewijn Rempt null at kde.org
Fri Sep 7 15:15:55 BST 2018


Git commit 6ed3c55fddfc497b5c052de96dab7edea39134a3 by Boudewijn Rempt, on behalf of Dmitry Kazakov.
Committed on 07/09/2018 at 12:49.
Pushed by rempt into branch 'krita/4.1'.

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/6ed3c55fddfc497b5c052de96dab7edea39134a3

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 50ad23521cb..5f53c6a1a0e 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1982,6 +1982,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 db655e5d762..df45458594c 100644
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -564,6 +564,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