Commit 55753fd9 authored by Dmitry Kazakov's avatar Dmitry Kazakov
Browse files

Fixed a "screwed" lines bug

It turned out that our "bended lines" bug consists from two different bugs.
1) Lack of tablet events (only in openGL mode)
2) A bug in Basic Smoothing algorithm (some whirls
   appeared even in QPainter canvas mode).

This patch fixes the second one. The bug was related to the fact that
the size of the control points for the bezier curves was *not limited*.
It resulted in lines bending, screwing and whirling effect. Now the size
of the control lines is always bounded, so the lines became much smoother.

But the first part of the "bended lines" bug is still not fixed, so openGL
mode will produce bends in lines.

CCMAIL:kimageshop@kde.org


The first one is the lack of tablet events in openGL mode, and the second
one was related to the
parent d213bc54
......@@ -278,12 +278,6 @@ void KisToolFreehand::mouseReleaseEvent(KoPointerEvent* e)
{
if (mode() == KisTool::PAINT_MODE &&
e->button() == Qt::LeftButton) {
if (m_smoothingOptions.smoothingType == KisSmoothingOptions::WEIGHTED_SMOOTHING) {
m_smoothingOptions.smoothingType = KisSmoothingOptions::SIMPLE_SMOOTHING;
m_helper->setSmoothness(m_smoothingOptions);
doStroke(e);
m_smoothingOptions.smoothingType = KisSmoothingOptions::WEIGHTED_SMOOTHING;
}
endStroke();
if (m_assistant) {
......
......@@ -35,6 +35,9 @@
#include <math.h>
#include <qnumeric.h> // for qIsNaN
//#define DEBUG_BEZIER_CURVES
struct KisToolFreehandHelper::Private
{
KisPaintingInformationBuilder *infoBuilder;
......@@ -143,6 +146,94 @@ void KisToolFreehandHelper::initPaint(KoPointerEvent *event,
}
}
void KisToolFreehandHelper::paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2,
QPointF tangent1, QPointF tangent2)
{
if (tangent1.isNull() || tangent2.isNull()) return;
const qreal maxSanePoint = 1e6;
QPointF controlTarget1;
QPointF controlTarget2;
// Shows the direction in which control points go
QPointF controlDirection1 = pi1.pos() + tangent1;
QPointF controlDirection2 = pi2.pos() - tangent2;
// Lines in the direction of the control points
QLineF line1(pi1.pos(), controlDirection1);
QLineF line2(pi2.pos(), controlDirection2);
// Lines to check whether the control points lay on the opposite
// side of the line
QLineF line3(controlDirection1, controlDirection2);
QLineF line4(pi1.pos(), pi2.pos());
QPointF intersection;
if (line3.intersect(line4, &intersection) == QLineF::BoundedIntersection) {
qreal controlLength = line4.length() / 2;
line1.setLength(controlLength);
line2.setLength(controlLength);
controlTarget1 = line1.p2();
controlTarget2 = line2.p2();
} else {
QLineF::IntersectType type = line1.intersect(line2, &intersection);
if (type == QLineF::NoIntersection ||
intersection.manhattanLength() > maxSanePoint) {
intersection = 0.5 * (pi1.pos() + pi2.pos());
qDebug() << "WARINING: there is no intersection point "
<< "in the basic smoothing algoriths";
}
controlTarget1 = intersection;
controlTarget2 = intersection;
}
// shows how near to the controlTarget the value raises
qreal coeff = 0.8;
qreal velocity1 = QLineF(QPointF(), tangent1).length();
qreal velocity2 = QLineF(QPointF(), tangent2).length();
Q_ASSERT(velocity1 > 0);
Q_ASSERT(velocity2 > 0);
qreal similarity = qMin(velocity1/velocity2, velocity2/velocity1);
// the controls should not differ more than 50%
similarity = qMax(similarity, 0.5);
// when the controls are symmetric, their size should be smaller
// to avoid corner-like curves
coeff *= 1 - qMax(0.0, similarity - 0.8);
Q_ASSERT(coeff > 0);
QPointF control1;
QPointF control2;
if (velocity1 > velocity2) {
control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1;
coeff *= similarity;
control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2;
} else {
control2 = pi2.pos() * (1.0 - coeff) + coeff * controlTarget2;
coeff *= similarity;
control1 = pi1.pos() * (1.0 - coeff) + coeff * controlTarget1;
}
paintBezierCurve(m_d->painterInfos,
pi1,
control1,
control2,
pi2);
}
void KisToolFreehandHelper::paint(KoPointerEvent *event)
{
KisPaintInformation info =
......@@ -218,29 +309,21 @@ void KisToolFreehandHelper::paint(KoPointerEvent *event)
}
if (m_d->smoothingOptions.smoothingType == KisSmoothingOptions::SIMPLE_SMOOTHING
|| m_d->smoothingOptions.smoothingType == KisSmoothingOptions::WEIGHTED_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()) /
(3.0 * (info.currentTime() - m_d->previousPaintInformation.currentTime()));
(info.currentTime() - m_d->previousPaintInformation.currentTime());
} else {
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;
paintBezierCurve(m_d->painterInfos,
m_d->olderPaintInformation,
control1,
control2,
m_d->previousPaintInformation);
(info.currentTime() - m_d->olderPaintInformation.currentTime());
paintBezierSegment(m_d->olderPaintInformation, m_d->previousPaintInformation,
m_d->previousTangent, newTangent);
m_d->previousTangent = newTangent;
}
m_d->olderPaintInformation = m_d->previousPaintInformation;
......@@ -296,15 +379,13 @@ void KisToolFreehandHelper::finishStroke()
if (m_d->haveTangent) {
m_d->haveTangent = false;
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;
paintBezierCurve(m_d->painterInfos,
m_d->olderPaintInformation,
control1,
control2,
m_d->previousPaintInformation);
QPointF newTangent = (m_d->previousPaintInformation.pos() - m_d->olderPaintInformation.pos()) /
(m_d->previousPaintInformation.currentTime() - m_d->olderPaintInformation.currentTime());
paintBezierSegment(m_d->olderPaintInformation,
m_d->previousPaintInformation,
m_d->previousTangent,
newTangent);
}
}
......@@ -348,6 +429,30 @@ void KisToolFreehandHelper::paintBezierCurve(PainterInfo *painterInfo,
const QPointF &control2,
const KisPaintInformation &pi2)
{
#ifdef DEBUG_BEZIER_CURVES
KisPaintInformation tpi1;
KisPaintInformation tpi2;
tpi1 = pi1;
tpi2 = pi2;
tpi1.setPressure(0.3);
tpi2.setPressure(0.3);
paintLine(m_d->painterInfos, tpi1, tpi2);
tpi1.setPressure(0.6);
tpi2.setPressure(0.3);
tpi1.setPos(pi1.pos());
tpi2.setPos(control1);
paintLine(m_d->painterInfos, tpi1, tpi2);
tpi1.setPos(pi2.pos());
tpi2.setPos(control2);
paintLine(m_d->painterInfos, tpi1, tpi2);
#endif
m_d->hasPaintAtLeastOnce = true;
m_d->strokesFacade->addJob(m_d->strokeId,
new FreehandStrokeStrategy::Data(m_d->resources->currentNode(),
......
......@@ -95,6 +95,10 @@ protected:
const QPointF &control2,
const KisPaintInformation &pi2);
private:
void paintBezierSegment(KisPaintInformation pi1, KisPaintInformation pi2,
QPointF tangent1, QPointF tangent2);
private slots:
void finishStroke();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment