1 /***************************************************************************
2 * Copyright (C) 2010 by Till Theato (root@ttill.de) *
3 * This file is part of Kdenlive (www.kdenlive.org). *
5 * Kdenlive is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
10 * Kdenlive is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
19 #include "cubicbezierspline.h"
23 static bool pointLessThan(const BPoint &a, const BPoint &b)
25 return a.p.x() < b.p.x();
28 CubicBezierSpline::CubicBezierSpline(QObject* parent) :
40 m_points.append(start);
52 CubicBezierSpline::CubicBezierSpline(const CubicBezierSpline& spline, QObject* parent) :
55 m_precision = spline.m_precision;
56 m_points = spline.m_points;
57 m_validSpline = false;
60 CubicBezierSpline& CubicBezierSpline::operator=(const CubicBezierSpline& spline)
62 m_precision = spline.m_precision;
63 m_points = spline.m_points;
67 void CubicBezierSpline::fromString(const QString& spline)
70 m_validSpline = false;
72 QStringList bpoints = spline.split('|');
73 foreach(const QString &bpoint, bpoints) {
74 QStringList points = bpoint.split('#');
75 QList <QPointF> values;
76 foreach(const QString &point, points) {
77 QStringList xy = point.split(';');
79 values.append(QPointF(xy.at(0).toDouble(), xy.at(1).toDouble()));
81 if (values.count() == 3) {
94 QString CubicBezierSpline::toString() const
97 foreach(const BPoint &p, m_points) {
98 spline << (QString::number(p.h1.x()) + ";" + QString::number(p.h1.y())
99 + "#" + QString::number(p.p.x()) + ";" + QString::number(p.p.y())
100 + "#" + QString::number(p.h2.x()) + ";" + QString::number(p.h2.y()));
102 return spline.join("|");
105 int CubicBezierSpline::setPoint(int ix, const BPoint& point)
107 m_points[ix] = point;
110 m_validSpline = false;
111 return m_points.indexOf(point); // in case it changed
114 QList <BPoint> CubicBezierSpline::points()
119 void CubicBezierSpline::removePoint(int ix)
121 m_points.removeAt(ix);
122 m_validSpline = false;
125 int CubicBezierSpline::addPoint(const BPoint& point)
127 m_points.append(point);
130 m_validSpline = false;
131 if (m_points.indexOf(point) == -1) {
132 // point changed during validation process
133 for (int i = 0; i < m_points.count(); ++i) {
134 // this condition should be sufficient, too
135 if (m_points.at(i).p == point.p)
139 return m_points.indexOf(point);
143 void CubicBezierSpline::setPrecision(int pre)
145 if (pre != m_precision) {
147 m_validSpline = false;
151 int CubicBezierSpline::getPrecision()
156 qreal CubicBezierSpline::value(qreal x, bool cont)
160 //x = qBound(m_spline.constBegin().key(), x, m_spline.constEnd().key());
161 //kDebug() << "....x" << x<<"bounddown"<<m_spline.constBegin().key()<<"up"<<m_spline.constEnd().key();
164 m_i = m_spline.constBegin();
165 if (m_i != m_spline.constBegin())
168 double diff = qAbs(x - m_i.key());
169 double y = m_i.value();
170 while (m_i != m_spline.constEnd()) {
171 if (qAbs(x - m_i.key()) > diff)
174 diff = qAbs(x - m_i.key());
178 return qBound((qreal)0.0, y, (qreal)1.0);
181 void CubicBezierSpline::validatePoints()
184 for (int i = 0; i < m_points.count() - 1; ++i) {
186 p2 = m_points.at(i+1);
187 p1.h2.setX(qBound(p1.p.x(), p1.h2.x(), p2.p.x()));
188 p2.h1.setX(qBound(p1.p.x(), p2.h1.x(), p2.p.x()));
194 void CubicBezierSpline::keepSorted()
196 qSort(m_points.begin(), m_points.end(), pointLessThan);
199 QPointF CubicBezierSpline::point(double t, const QList< QPointF >& points)
201 // coefficients from Bernstein basis polynomial of degree 3
202 double c1 = (1-t) * (1-t) * (1-t);
203 double c2 = 3 * t * (1-t) * (1-t);
204 double c3 = 3 * t * t * (1-t);
205 double c4 = t * t * t;
207 return QPointF(points[0].x()*c1 + points[1].x()*c2 + points[2].x()*c3 + points[3].x()*c4,
208 points[0].y()*c1 + points[1].y()*c2 + points[2].y()*c3 + points[3].y()*c4);
211 void CubicBezierSpline::update()
216 m_validSpline = true;
219 QList <QPointF> points;
221 for (int i = 0; i < m_points.count() - 1; ++i) {
223 points << m_points.at(i).p
225 << m_points.at(i+1).h1
226 << m_points.at(i+1).p;
228 int numberOfValues = (int)((points[3].x() - points[0].x()) * m_precision * 5);
229 if (numberOfValues == 0)
231 double step = 1 / (double)numberOfValues;
234 p = point(t, points);
235 m_spline.insert(p.x(), p.y());
239 /*QMap<double, double>::const_iterator i = m_spline.constBegin();
240 kDebug()<<"////////////spline/////////////";
241 while (i != m_spline.constEnd()) {
242 kDebug() << i.key() << i.value();
245 kDebug()<<"////////////spline/////////////end";*/
248 #include "cubicbezierspline.moc"