19 : m_position(position), m_isCorner(setAsCorner)
23 : m_position(x, y), m_isCorner(setAsCorner)
79 Data(
const Data& data) : QSharedData() {
89 mutable bool validSpline {
false};
91 mutable bool validU8Transfer {
false};
93 mutable bool validU16Transfer {
false};
95 mutable bool validFTransfer {
false};
102 template<
typename _T_,
typename _T2_>
106void KisCubicCurve::Data::updateSpline()
108 if (validSpline)
return;
110 spline.createSpline(points);
113void KisCubicCurve::Data::invalidate()
116 validFTransfer =
false;
117 validU16Transfer =
false;
120void KisCubicCurve::Data::keepSorted()
125qreal KisCubicCurve::Data::value(qreal x)
131 x = qBound(points.first().x(), x, points.last().x());
132 qreal
y = spline.getValue(x);
133 return qBound(qreal(0.0), y, qreal(1.0));
136template<
typename _T_,
typename _T2_>
137void KisCubicCurve::Data::updateTransfer(
QVector<_T_>* transfer,
bool& valid, _T2_ min, _T2_ max,
int size)
139 if (!valid || transfer->size() != size) {
140 if (transfer->size() != size) {
141 transfer->resize(size);
143 qreal end = 1.0 / (
size - 1);
144 for (
int i = 0; i <
size; ++i) {
147 val = qBound(min, val, max);
148 (*transfer)[i] = val;
162 d->data->points.append({ 0.0, 0.0,
false });
163 d->data->points.append({ 1.0, 1.0,
false });
170 d->data->points.reserve(
points.size());
171 Q_FOREACH(
const QPointF
p,
points) {
172 d->data->points.append({
p,
false });
174 d->data->keepSorted();
182 d->data->keepSorted();
219 Q_FOREACH (
const QString &entry,
data) {
220 const QStringList entryData = entry.split(
',', Qt::SkipEmptyParts);
236 bool isCorner =
false;
237 for (
int i = 2; i < entryData.size(); ++i) {
238 if (entryData[i] ==
"is_corner") {
242 points.append({ x, y, isCorner });
255 if (&curve !=
this) {
263 if (
d->data == curve.
d->data)
return true;
264 return d->data->points == curve.
d->data->points;
269 qreal
value =
d->data->value(x);
277 pointPositions.append(point.
position());
279 return pointPositions;
284 return d->data->points;
290 d->data->points.clear();
291 Q_FOREACH(
const QPointF &
p,
points) {
292 d->data->points.append({
p,
false });
294 d->data->invalidate();
301 d->data->invalidate();
307 d->data->points[idx] = point;
308 d->data->keepSorted();
309 d->data->invalidate();
314 setPoint(idx, { position, setAsCorner });
325 d->data->points[idx].setPosition(position);
326 d->data->keepSorted();
327 d->data->invalidate();
333 d->data->points[idx].setAsCorner(setAsCorner);
334 d->data->invalidate();
340 d->data->points.append(point);
341 d->data->keepSorted();
342 d->data->invalidate();
344 return d->data->points.indexOf(point);
349 return addPoint({ position, setAsCorner });
354 return addPoint({ position,
false });
360 d->data->points.removeAt(idx);
361 d->data->invalidate();
368 if (
points.first().x() != 0.0 ||
points.first().y() != 0.0 ||
373 for (
int i = 1; i <
points.size() - 1; i++) {
397 return d->data->name;
402 const qreal maxValue = transfer.size() - 1;
404 const qreal bilinearX = qBound(0.0, maxValue * normalizedValue, maxValue);
405 const qreal xFloored = std::floor(bilinearX);
406 const qreal xCeiled = std::ceil(bilinearX);
408 const qreal t = bilinearX - xFloored;
410 constexpr qreal
eps = 1e-6;
412 qreal newValue = normalizedValue;
415 newValue = transfer[int(xFloored)];
416 }
else if (t > (1.0 -
eps)) {
417 newValue = transfer[int(xCeiled)];
419 qreal a = transfer[int(xFloored)];
420 qreal b = transfer[int(xCeiled)];
422 newValue = a + t * (b - a);
430 d->data->name =
name;
440 if(
d->data->points.count() < 1)
444 sCurve += QString::number(point.
x());
446 sCurve += QString::number(point.
y());
449 sCurve +=
"is_corner";
464 d->data->updateTransfer<quint16,
int>(&
d->data->u16Transfer,
d->data->validU16Transfer, 0x0, 0xFFFF, size);
465 return d->data->u16Transfer;
470 d->data->updateTransfer<qreal, qreal>(&
d->data->fTransfer,
d->data->validFTransfer, 0.0, 1.0, size);
471 return d->data->fTransfer;
float value(const T *src, size_t ch)
bool operator==(const KisCubicCurvePoint &other) const
KisCubicCurvePoint()=default
void setAsCorner(bool newIsSetAsCorner)
const QPointF & position() const
bool isSetAsCorner() const
void setPosition(const QPointF &newPosition)
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER(cond)
static bool pointLessThan(const KisCubicCurvePoint &a, const KisCubicCurvePoint &b)
double toDouble(const QString &str, bool *ok=nullptr)
int size(const Forest< T > &forest)
constexpr std::enable_if< sizeof...(values)==0, size_t >::type max()
bool operator==(const KisCubicCurve &curve) const
QVector< quint16 > u16Transfer
const QVector< quint16 > uint16Transfer(int size=256) const
void setPoint(int idx, const KisCubicCurvePoint &point)
const QVector< qreal > floatTransfer(int size=256) const
void setPointPosition(int idx, const QPointF &position)
QVector< quint8 > u8Transfer
KisCubicCurve & operator=(const KisCubicCurve &curve)
QList< KisCubicCurvePoint > points
Q_DECL_DEPRECATED void fromString(const QString &)
void setPointAsCorner(int idx, bool setAsCorner)
void setPoints(const QList< QPointF > &points)
void setName(const QString &name)
void updateTransfer(QVector< _T_ > *transfer, bool &valid, _T2_ min, _T2_ max, int size)
void removePoint(int idx)
bool isConstant(qreal c) const
KisCubicSpline< KisCubicCurvePoint, qreal > spline
QSharedDataPointer< Data > data
static qreal interpolateLinear(qreal normalizedValue, const QVector< qreal > &transfer)
QVector< qreal > fTransfer
const QList< KisCubicCurvePoint > & curvePoints() const
int addPoint(const KisCubicCurvePoint &point)