Commit 08f1cea6 authored by Agata Cacko's avatar Agata Cacko

Fix tilt elevation curve not working correctly

Before this commit, tilt elevation curve was broken because
of addition of spinboxes which didn't allow for reverse range.
This commit provides reverse range calculations for spinboxes
and fixes multiple conversions between values inside curve widget.

BUG:399846
parent 1266d74a
......@@ -276,6 +276,7 @@ set(kritaui_LIB_SRCS
widgets/KisGamutMaskToolbar.cpp
utils/kis_document_aware_spin_box_unit_manager.cpp
utils/KisSpinBoxSplineUnitConverter.cpp
input/kis_input_manager.cpp
input/kis_input_manager_p.cpp
......
......@@ -26,6 +26,7 @@ ecm_add_tests(
kis_prescaled_projection_test.cpp
kis_asl_layer_style_serializer_test.cpp
kis_animation_importer_test.cpp
KisSpinBoxSplineUnitConverterTest.cpp
LINK_LIBRARIES kritaui Qt5::Test
NAME_PREFIX "libs-ui-"
......
/*
* Copyright (c) 2015 Agata Cacko <cacko.azg@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 <QTest>
#include <testutil.h>
#include <kistest.h>
#include <KisSpinBoxSplineUnitConverterTest.h>
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationToCurve_data()
{
QTest::addColumn<int>("x");
QTest::addColumn<int>("min");
QTest::addColumn<int>("max");
QTest::addColumn<double>("expected");
QTest::newRow("0.6 in (0, 10) = 6") << 6 << 0 << 10 << 0.6;
}
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationToCurve()
{
QFETCH(int, x);
QFETCH(int, min);
QFETCH(int, max);
QFETCH(double, expected);
qreal result = converter.io2sp(x, min, max);
QCOMPARE(result, expected);
}
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationToSpinBox_data()
{
QTest::addColumn<double>("x");
QTest::addColumn<int>("min");
QTest::addColumn<int>("max");
QTest::addColumn<int>("expected");
QTest::newRow("0.4 in (0, 10) = 4") << 0.4 << 0 << 10 << 4;
}
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationToSpinBox()
{
QFETCH(double, x);
QFETCH(int, min);
QFETCH(int, max);
QFETCH(int, expected);
int result = converter.sp2io(x, min, max);
QCOMPARE(result, expected);
}
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationTwoWay_data()
{
QTest::addColumn<double>("xDouble");
QTest::addColumn<int>("min");
QTest::addColumn<int>("max");
QTest::addColumn<int>("xInt");
QTest::newRow("0.5 in (0, 10) = 5") << 0.5 << 0 << 10 << 5;
QTest::newRow("0.3 in (0, 10) = 3") << 0.3 << 0 << 10 << 3;
QTest::newRow("0.7 in (0, 10) = 7") << 0.7 << 0 << 10 << 7;
QTest::newRow("0.5 in (10, 0) = 5") << 0.5 << 10 << 0 << 5;
QTest::newRow("0.7 in (10, 0) = 3") << 0.7 << 10 << 0 << 3;
QTest::newRow("0.3 in (10, 0) = 7") << 0.3 << 10 << 0 << 7;
}
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationTwoWay()
{
QFETCH(double, xDouble);
QFETCH(int, min);
QFETCH(int, max);
QFETCH(int, xInt);
int resultInt = converter.sp2io(xDouble, min, max);
QCOMPARE(resultInt, xInt);
double resultDouble = converter.io2sp(xInt, min, max);
QCOMPARE(resultDouble, xDouble);
}
void KisSpinBoxSplineUnitConverterTest::testCurveCalculationCase64()
{
int inX = 64;
int min = 90, max = 0;
double resultDouble = converter.io2sp(inX, min, max);
int resultInt = converter.sp2io(resultDouble, min, max);
QCOMPARE(resultInt, inX);
}
KISTEST_MAIN(KisSpinBoxSplineUnitConverterTest)
/*
* Copyright (c) 2015 Agata Cacko <cacko.azh@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_ANIMATION_EXPORTER_TEST_H
#define KIS_ANIMATION_EXPORTER_TEST_H
#include <QtTest>
#include <KisSpinBoxSplineUnitConverter.h>
/**
* KisSpinBoxSplineUnitConverterTest contains tests
* for class KisSpinBoxSplineUnitConverter
*/
class KisSpinBoxSplineUnitConverterTest : public QObject
{
Q_OBJECT
KisSpinBoxSplineUnitConverter converter;
private Q_SLOTS:
void testCurveCalculationToSpinBox();
void testCurveCalculationToSpinBox_data();
void testCurveCalculationToCurve();
void testCurveCalculationToCurve_data();
void testCurveCalculationTwoWay();
void testCurveCalculationTwoWay_data();
void testCurveCalculationCase64();
};
#endif
#include "KisSpinBoxSplineUnitConverter.h"
#include <QtMath>
#include <kis_debug.h>
double KisSpinBoxSplineUnitConverter::io2sp(int x, int min, int max)
{
int reversedRange = max - min > 0 ? 1 : -1; // tilt elevation has range (90; 0)
int rangeLen = qAbs(max - min);
double response = reversedRange * double(x - min) / rangeLen;
return response;
}
int KisSpinBoxSplineUnitConverter::sp2io(double x, int min, int max)
{
int rangeLen = max - min; // tilt elevation has range (90; 0)
int response = qRound(x*rangeLen) + min;
return response;
}
/*
* Copyright (c) 2017 Agata Cacko <cacko.azh@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_SPIN_BOX_SPLINE_UNITS_CONVERTER_H
#define KIS_SPIN_BOX_SPLINE_UNITS_CONVERTER_H
#include <kritaui_export.h>
/**
* KisSpinBoxSplineUnitConverter is a class that converts points
* from ranges(0, 1) to ranges (min, max).
* In case of reverted ranges (min > max),
* smaller values from range (0, 1) correspond
* to bigger values from range (min, max)
* and the other way around.
* Example:
* 3 from (0, 10) is 0.3 from (0, 1)
* 3 from (10, 0) is 0.7 from (0, 1)
*/
class KRITAUI_EXPORT KisSpinBoxSplineUnitConverter
{
public:
double io2sp(int x, int min, int max);
int sp2io(double x, int min, int max);
};
#endif // KIS_SPIN_BOX_SPLINE_UNITS_CONVERTER_H
......@@ -103,11 +103,15 @@ void KisCurveWidget::setupInOutControls(QSpinBox *in, QSpinBox *out, int inMin,
d->m_outMin = outMin;
d->m_outMax = outMax;
d->m_intIn->setRange(d->m_inMin, d->m_inMax);
int realInMin = qMin(inMin, inMax); // tilt elevation has range (90, 0), which QSpinBox can't handle
int realInMax = qMax(inMin, inMax);
d->m_intIn->setRange(realInMin, realInMax);
d->m_intOut->setRange(d->m_outMin, d->m_outMax);
connect(d->m_intIn, SIGNAL(valueChanged(int)), this, SLOT(inOutChanged(int)), Qt::UniqueConnection);
connect(d->m_intOut, SIGNAL(valueChanged(int)), this, SLOT(inOutChanged(int)), Qt::UniqueConnection);
d->syncIOControls();
}
......@@ -132,24 +136,31 @@ void KisCurveWidget::inOutChanged(int)
pt.setX(d->io2sp(d->m_intIn->value(), d->m_inMin, d->m_inMax));
pt.setY(d->io2sp(d->m_intOut->value(), d->m_outMin, d->m_outMax));
bool newPoint = false;
if (d->jumpOverExistingPoints(pt, d->m_grab_point_index)) {
newPoint = true;
d->m_curve.setPoint(d->m_grab_point_index, pt);
d->m_grab_point_index = d->m_curve.points().indexOf(pt);
emit pointSelectedChanged();
} else
} else {
pt = d->m_curve.points()[d->m_grab_point_index];
}
if (!newPoint) {
// if there is a new Point, no point in rewriting values in spinboxes
d->m_intIn->blockSignals(true);
d->m_intOut->blockSignals(true);
d->m_intIn->blockSignals(true);
d->m_intOut->blockSignals(true);
d->m_intIn->setValue(d->sp2io(pt.x(), d->m_inMin, d->m_inMax));
d->m_intOut->setValue(d->sp2io(pt.y(), d->m_outMin, d->m_outMax));
d->m_intIn->setValue(d->sp2io(pt.x(), d->m_inMin, d->m_inMax));
d->m_intOut->setValue(d->sp2io(pt.y(), d->m_outMin, d->m_outMax));
d->m_intIn->blockSignals(false);
d->m_intOut->blockSignals(false);
d->m_intIn->blockSignals(false);
d->m_intOut->blockSignals(false);
}
d->setCurveModified();
d->setCurveModified(false);
}
......
......@@ -21,6 +21,7 @@
#include <kis_cubic_curve.h>
#include <QApplication>
#include <QPalette>
#include <KisSpinBoxSplineUnitConverter.h>
enum enumState {
ST_NORMAL,
......@@ -34,6 +35,7 @@ class Q_DECL_HIDDEN KisCurveWidget::Private
{
KisCurveWidget *m_curveWidget;
KisSpinBoxSplineUnitConverter unitConverter;
public:
......@@ -88,7 +90,7 @@ public:
/**
* Common update routines
*/
void setCurveModified();
void setCurveModified(bool rewriteSpinBoxesValues);
void setCurveRepaint();
......@@ -96,6 +98,7 @@ public:
* Convert working range of
* In/Out controls to normalized
* range of spline (and reverse)
* See notes on KisSpinBoxSplineUnitConverter
*/
double io2sp(int x, int min, int max);
int sp2io(double x, int min, int max);
......@@ -139,14 +142,12 @@ KisCurveWidget::Private::Private(KisCurveWidget *parent)
double KisCurveWidget::Private::io2sp(int x, int min, int max)
{
int rangeLen = max - min;
return double(x - min) / rangeLen;
return unitConverter.io2sp(x, min, max);
}
int KisCurveWidget::Private::sp2io(double x, int min, int max)
{
int rangeLen = max - min;
return int(x*rangeLen + 0.5) + min;
return unitConverter.sp2io(x, min, max);
}
......@@ -155,9 +156,10 @@ bool KisCurveWidget::Private::jumpOverExistingPoints(QPointF &pt, int skipIndex)
Q_FOREACH (const QPointF &it, m_curve.points()) {
if (m_curve.points().indexOf(it) == skipIndex)
continue;
if (fabs(it.x() - pt.x()) < POINT_AREA)
if (fabs(it.x() - pt.x()) < POINT_AREA) {
pt.rx() = pt.x() >= it.x() ?
it.x() + POINT_AREA : it.x() - POINT_AREA;
}
}
return (pt.x() >= 0 && pt.x() <= 1.);
}
......@@ -243,9 +245,12 @@ void KisCurveWidget::Private::syncIOControls()
}
}
void KisCurveWidget::Private::setCurveModified()
void KisCurveWidget::Private::setCurveModified(bool rewriteSpinBoxesValues = true)
{
syncIOControls();
if (rewriteSpinBoxesValues) {
syncIOControls();
}
m_splineDirty = true;
m_curveWidget->update();
m_curveWidget->emit modified();
......
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