Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kquickcharts for openSUSE:Factory 
checked in at 2021-06-16 20:34:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kquickcharts (Old)
 and      /work/SRC/openSUSE:Factory/.kquickcharts.new.32437 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kquickcharts"

Wed Jun 16 20:34:08 2021 rev:19 rq:899759 version:5.83.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/kquickcharts/kquickcharts.changes        
2021-05-10 15:37:28.666017441 +0200
+++ /work/SRC/openSUSE:Factory/.kquickcharts.new.32437/kquickcharts.changes     
2021-06-16 20:35:46.507215832 +0200
@@ -1,0 +2,14 @@
+Sat Jun  5 11:59:10 UTC 2021 - Christophe Giboudeaux <[email protected]>
+
+- Update to 5.83.0
+  * New feature release
+  * For more details please see:
+  * https://kde.org/announcements/frameworks/5/5.83.0
+- Changes since 5.82.0:
+  * Implement monotonic cubic interpolation for line charts (kde#435268)
+  * Prevent an infinite loop in LegendLayout when minTotalWidth equals 
available
+  * Reduce severity of column not found to debug
+  * Bump required CMake version to 3.16
+  * Expose preferredWidth as a property on LegendLayout and Legend
+
+-------------------------------------------------------------------

Old:
----
  kquickcharts-5.82.0.tar.xz
  kquickcharts-5.82.0.tar.xz.sig

New:
----
  kquickcharts-5.83.0.tar.xz
  kquickcharts-5.83.0.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kquickcharts.spec ++++++
--- /var/tmp/diff_new_pack.oWV0VI/_old  2021-06-16 20:35:46.919216535 +0200
+++ /var/tmp/diff_new_pack.oWV0VI/_new  2021-06-16 20:35:46.923216542 +0200
@@ -16,14 +16,14 @@
 #
 
 
-%define _tar_path 5.82
+%define _tar_path 5.83
 # Full KF5 version (e.g. 5.33.0)
 %{!?_kf5_version: %global _kf5_version %{version}}
 # Last major and minor KF5 version (e.g. 5.33)
 %{!?_kf5_bugfix_version: %define _kf5_bugfix_version %(echo %{_kf5_version} | 
awk -F. '{print $1"."$2}')}
 %bcond_without lang
 Name:           kquickcharts
-Version:        5.82.0
+Version:        5.83.0
 Release:        0
 Summary:        Set of charts for QtQuick applications
 License:        LGPL-2.1-or-later


++++++ kquickcharts-5.82.0.tar.xz -> kquickcharts-5.83.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kquickcharts-5.82.0/.gitignore 
new/kquickcharts-5.83.0/.gitignore
--- old/kquickcharts-5.82.0/.gitignore  2021-05-06 10:45:40.000000000 +0200
+++ new/kquickcharts-5.83.0/.gitignore  2021-06-05 10:58:28.000000000 +0200
@@ -6,3 +6,4 @@
 /build
 .clangd
 /cmake-build*
+.cache
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kquickcharts-5.82.0/CMakeLists.txt 
new/kquickcharts-5.83.0/CMakeLists.txt
--- old/kquickcharts-5.82.0/CMakeLists.txt      2021-05-06 10:45:40.000000000 
+0200
+++ new/kquickcharts-5.83.0/CMakeLists.txt      2021-06-05 10:58:28.000000000 
+0200
@@ -1,12 +1,12 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.16)
 
-set(KF_VERSION "5.82.0") # handled by release scripts
-set(KF_DEP_VERSION "5.82.0") # handled by release scripts
+set(KF_VERSION "5.83.0") # handled by release scripts
+set(KF_DEP_VERSION "5.83.0") # handled by release scripts
 
 project(KQuickCharts VERSION ${KF_VERSION})
 
 include(FeatureSummary)
-find_package(ECM 5.82.0 NO_MODULE)
+find_package(ECM 5.83.0 NO_MODULE)
 set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake 
Modules." URL "https://commits.kde.org/extra-cmake-modules";)
 feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND 
FATAL_ON_MISSING_REQUIRED_PACKAGES)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kquickcharts-5.82.0/src/CMakeLists.txt 
new/kquickcharts-5.83.0/src/CMakeLists.txt
--- old/kquickcharts-5.82.0/src/CMakeLists.txt  2021-05-06 10:45:40.000000000 
+0200
+++ new/kquickcharts-5.83.0/src/CMakeLists.txt  2021-06-05 10:58:28.000000000 
+0200
@@ -37,8 +37,6 @@
 
 qt5_add_resources(quickcharts_QRC shaders/shaders.qrc)
 
-add_definitions(-DQT_NO_KEYWORDS)
-
 ecm_qt_declare_logging_category(quickcharts_SRCS
     HEADER charts_general_logging.h
     IDENTIFIER GENERAL
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kquickcharts-5.82.0/src/LineChart.cpp 
new/kquickcharts-5.83.0/src/LineChart.cpp
--- old/kquickcharts-5.82.0/src/LineChart.cpp   2021-05-06 10:45:40.000000000 
+0200
+++ new/kquickcharts-5.83.0/src/LineChart.cpp   2021-06-05 10:58:28.000000000 
+0200
@@ -7,19 +7,22 @@
 
 #include "LineChart.h"
 
+#include <cmath>
+
 #include <QPainter>
 #include <QPainterPath>
 #include <QQuickWindow>
-#include <numeric>
 
 #include "RangeGroup.h"
 #include "datasource/ChartDataSource.h"
 #include "scenegraph/LineChartNode.h"
 #include "scenegraph/LineGridNode.h"
 
-QVector<QPointF> solveControlPoints(const QVector<QPointF> input);
-QVector<QPair<QPointF, QPointF>> calculateControlPoints(const 
QVector<QVector2D> &points, qreal height);
-QVector<QVector2D> interpolate(const QVector<QVector2D> &points, qreal height);
+static const float PixelsPerStep = 1.0;
+
+QVector<QVector2D> interpolate(const QVector<QVector2D> &points, float height);
+QVector<float> calculateTangents(const QVector<QVector2D> &points, float 
height);
+QVector2D cubicHermite(const QVector2D &first, const QVector2D &second, float 
step, float mFirst, float mSecond);
 
 QColor colorWithAlpha(const QColor &color, qreal opacity)
 {
@@ -326,40 +329,6 @@
     node->setValues(values);
 }
 
-QVector<QVector2D> interpolate(const QVector<QVector2D> &points, qreal height) 
//, qreal start, qreal end, qreal height)
-{
-    if (points.size() < 2) {
-        return points;
-    }
-
-    auto controlPoints = calculateControlPoints(points, height);
-
-    QPainterPath path;
-    path.moveTo(0.0, points.first().y() * height);
-
-    for (int i = 0; i < points.size() - 1; ++i) {
-        auto controlPoint = controlPoints.at(i);
-        auto nextPoint = QPointF{points.at(i + 1).x(), points.at(i + 1).y() * 
height};
-        path.cubicTo(controlPoint.first, controlPoint.second, nextPoint);
-    }
-
-    QVector<QVector2D> result;
-
-    const auto polygons = path.toSubpathPolygons();
-    auto pointCount = std::accumulate(polygons.begin(), polygons.end(), 0, 
[](int current, const QPolygonF &polygon) {
-        return current + polygon.size();
-    });
-    result.reserve(pointCount);
-
-    for (const auto &polygon : polygons) {
-        for (auto point : polygon) {
-            result.append(QVector2D{float(point.x()), float(point.y() / 
height)});
-        }
-    }
-
-    return result;
-}
-
 void LineChart::createPointDelegates(const QVector<QVector2D> &values, int 
sourceIndex)
 {
     auto valueSource = valueSources().at(sourceIndex);
@@ -397,80 +366,133 @@
     attached->setShortName(shortNameSource() ? 
shortNameSource()->item(sourceIndex).toString() : QString{});
 }
 
-QVector<QPair<QPointF, QPointF>> calculateControlPoints(const 
QVector<QVector2D> &points, qreal height)
+// Smoothly interpolate between points, using monotonic cubic interpolation.
+QVector<QVector2D> interpolate(const QVector<QVector2D> &points, float height)
 {
-    // This is based on
-    // 
https://www.codeproject.com/Articles/31859/Draw-a-Smooth-Curve-through-a-Set-of-2D-Points-wit
-    // and calculates the control points based on the derivative of the curve.
+    if (points.size() < 2) {
+        return points;
+    }
 
-    auto count = points.size() - 1;
-    QVector<QPair<QPointF, QPointF>> result(count);
+    auto tangents = calculateTangents(points, height);
 
-    const auto first = QPointF{points.first().x(), points.first().y() * 
height};
-    const auto last = QPointF{points.last().x(), points.last().y() * height};
+    QVector<QVector2D> result;
+
+    auto current = QVector2D{0.0, points.first().y() * height};
+    result.append(QVector2D{0.0, points.first().y()});
 
-    if (count == 1) {
-        auto &controlPoint = result[0];
+    for (int i = 0; i < points.size() - 1; ++i) {
+        auto next = QVector2D{points.at(i + 1).x(), points.at(i + 1).y() * 
height};
 
-        controlPoint.first.rx() = (2.0 * first.x() + last.x()) / 3.0;
-        controlPoint.first.ry() = (2.0 * first.y() + last.y()) / 3.0;
+        auto currentTangent = tangents.at(i);
+        auto nextTangent = tangents.at(i + 1);
 
-        controlPoint.second.rx() = 2.0 * controlPoint.first.x() - first.x();
-        controlPoint.second.ry() = 2.0 * controlPoint.first.y() - first.y();
+        auto stepCount = int(std::max(1.0f, (next.x() - current.x()) / 
PixelsPerStep));
+        auto stepSize = (next.x() - current.x()) / stepCount;
 
-        return result;
+        if (stepCount == 1 || qFuzzyIsNull(next.y() - current.y())) {
+            result.append(QVector2D{next.x(), next.y() / height});
+            current = next;
+            continue;
+        }
+
+        for (auto delta = current.x(); delta < next.x(); delta += stepSize) {
+            auto interpolated = cubicHermite(current, next, delta, 
currentTangent, nextTangent);
+            interpolated.setY(interpolated.y() / height);
+            result.append(interpolated);
+        }
+
+        current = next;
     }
 
-    QVector<QPointF> coordinates(count);
-    std::generate_n(coordinates.begin() + 1, count - 2, [&points, height, i = 
1]() mutable {
-        auto x = 4.0 * points[i].x() + 2.0 * points[i + 1].x();
-        auto y = 4.0 * points[i].y() * height + 2.0 * points[i + 1].y() * 
height;
-        i++;
-        return QPointF{x, y};
-    });
+    current.setY(current.y() / height);
+    result.append(current);
 
-    coordinates.first().rx() = first.x() + 2.0 * points.at(1).x();
-    coordinates.first().ry() = first.y() + 2.0 * points.at(1).y() * height;
-    coordinates.last().rx() = (8.0 * points.at(count - 1).x() + last.x()) / 
2.0;
-    coordinates.last().ry() = (8.0 * points.at(count - 1).y() * height + 
last.y()) / 2.0;
+    return result;
+}
 
-    const auto solved = solveControlPoints(coordinates);
+// This calculates the tangents for monotonic cubic spline interpolation.
+// See https://en.wikipedia.org/wiki/Monotone_cubic_interpolation for details.
+QVector<float> calculateTangents(const QVector<QVector2D> &points, float 
height)
+{
+    QVector<float> secantSlopes;
+    secantSlopes.reserve(points.size());
 
-    for (int i = 0; i < count; ++i) {
-        auto &controlPoint = result[i];
-        controlPoint.first = solved[i];
+    QVector<float> tangents;
+    tangents.reserve(points.size());
 
-        if (i < count - 1) {
-            controlPoint.second = QPointF{2.0 * points.at(i + 1).x() - 
solved.at(i + 1).x(), //
-                                          2.0 * points.at(i + 1).y() * height 
- solved.at(i + 1).y()};
+    float previousSlope = 0.0;
+    float slope = 0.0;
+
+    for (int i = 0; i < points.size() - 1; ++i) {
+        auto current = points.at(i);
+        auto next = points.at(i + 1);
+
+        previousSlope = slope;
+        slope = (next.y() * height - current.y() * height) / (next.x() - 
current.x());
+
+        secantSlopes.append(slope);
+
+        if (i == 0) {
+            tangents.append(slope);
+        } else if (previousSlope * slope < 0.0) {
+            tangents.append(0.0);
         } else {
-            controlPoint.second = QPointF{(last.x() + solved.at(count - 
1).x()) / 2.0, //
-                                          (last.y() + solved.at(count - 
1).y()) / 2.0};
+            tangents.append((previousSlope + slope) / 2.0);
         }
     }
+    tangents.append(secantSlopes.last());
 
-    return result;
-}
+    for (int i = 0; i < points.size() - 1; ++i) {
+        auto slope = secantSlopes.at(i);
 
-QVector<QPointF> solveControlPoints(const QVector<QPointF> input)
-{
-    auto count = input.size();
-    QVector<QPointF> result(count);
-    QVector<double> temp(count);
+        if (qFuzzyIsNull(slope)) {
+            tangents[i] = 0.0;
+            tangents[i + 1] = 0.0;
+            continue;
+        }
 
-    double b = 2.0;
-    result.first() = input.first() / b;
+        auto alpha = tangents.at(i) / slope;
+        auto beta = tangents.at(i + 1) / slope;
 
-    for (int i = 1; i < count; ++i) {
-        temp[i] = 1.0 / b;
-        b = (i < count - 1 ? 4.0 : 3.5) - temp[i];
-        result[i].rx() = (input[i].x() - result[i - 1].x()) / b;
-        result[i].ry() = (input[i].y() - result[i - 1].y()) / b;
-    }
+        if (alpha < 0.0) {
+            tangents[i] = 0.0;
+        }
 
-    for (int i = 1; i < count; ++i) {
-        result[count - i - 1] -= temp[count - i] * result[count - i];
+        if (beta < 0.0) {
+            tangents[i + 1] = 0.0;
+        }
+
+        auto length = alpha * alpha + beta * beta;
+        if (length > 9) {
+            auto tau = 3.0 / sqrt(length);
+            tangents[i] = tau * alpha * slope;
+            tangents[i + 1] = tau * beta * slope;
+        }
     }
 
+    return tangents;
+}
+
+// Cubic Hermite Interpolation between two points
+// Given two points, an X value between those two points and two tangents, this
+// will perform cubic hermite interpolation between the two points.
+// See https://en.wikipedia.org/wiki/Cubic_Hermite_spline for details as well 
as
+// the above mentioned article on monotonic interpolation.
+QVector2D cubicHermite(const QVector2D &first, const QVector2D &second, float 
step, float mFirst, float mSecond)
+{
+    const auto delta = second.x() - first.x();
+    const auto t = (step - first.x()) / delta;
+
+    // Hermite basis values
+    // h??????(t) = 2t?? - 3t?? + 1
+    const auto h00 = 2.0f * std::pow(t, 3.0f) - 3.0f * std::pow(t, 2.0f) + 
1.0f;
+    // h??????(t) = t?? - 2t?? + t
+    const auto h10 = std::pow(t, 3.0f) - 2.0f * std::pow(t, 2.0f) + t;
+    // h??????(t) = -2t?? + 3t??
+    const auto h01 = -2.0f * std::pow(t, 3.0f) + 3.0f * std::pow(t, 2.0f);
+    // h??????(t) = t?? - t??
+    const auto h11 = std::pow(t, 3.0f) - std::pow(t, 2.0f);
+
+    auto result = QVector2D{step, first.y() * h00 + delta * mFirst * h10 + 
second.y() * h01 + delta * mSecond * h11};
     return result;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kquickcharts-5.82.0/src/datasource/ModelSource.cpp 
new/kquickcharts-5.83.0/src/datasource/ModelSource.cpp
--- old/kquickcharts-5.82.0/src/datasource/ModelSource.cpp      2021-05-06 
10:45:40.000000000 +0200
+++ new/kquickcharts-5.83.0/src/datasource/ModelSource.cpp      2021-06-05 
10:58:28.000000000 +0200
@@ -80,7 +80,7 @@
     }
 
     if (!m_indexColumns && (m_column < 0 || m_column > 
m_model->columnCount())) {
-        qCWarning(DATASOURCE) << "ModelSource: Invalid column" << m_column;
+        qCDebug(DATASOURCE) << "ModelSource: Invalid column" << m_column;
         return QVariant{};
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kquickcharts-5.82.0/src/decorations/LegendLayout.cpp 
new/kquickcharts-5.83.0/src/decorations/LegendLayout.cpp
--- old/kquickcharts-5.82.0/src/decorations/LegendLayout.cpp    2021-05-06 
10:45:40.000000000 +0200
+++ new/kquickcharts-5.83.0/src/decorations/LegendLayout.cpp    2021-06-05 
10:58:28.000000000 +0200
@@ -306,7 +306,7 @@
         // If the minimum width is less than our width, but the maximum is
         // larger, we found a correct solution since we can resize the items to
         // fit within the provided bounds.
-        if (minTotalWidth < availableWidth && maxTotalWidth >= availableWidth) 
{
+        if (minTotalWidth <= availableWidth && maxTotalWidth >= 
availableWidth) {
             break;
         }
 

Reply via email to