File indexing completed on 2024-06-16 04:17:32

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "MyPaintCurveRangeModel.h"
0008 #include "kis_algebra_2d.h"
0009 #include "kis_cubic_curve.h"
0010 #include <lager/lenses.hpp>
0011 #include <lager/constant.hpp>
0012 #include <KisZug.h>
0013 #include <KisDynamicSensorFactoryRegistry.h>
0014 #include <KisCurveRangeModel.h>
0015 
0016 namespace {
0017     auto formatQRealAsString = [] (qreal value) {
0018         return QString("%1").arg(value, 0, 'f', 2);
0019     };
0020 
0021     auto formatQRealAsStringWithSuffix = [] (const QString &suffix) {
0022         return [suffix] (qreal value) {
0023             return QString("%1%2").arg(value, 0, 'f', 2).arg(suffix);
0024         };
0025     };
0026 
0027 
0028     auto curveToNormalizedCurve = lager::lenses::getset(
0029         [] (const std::tuple<QString, QRectF> &curveData)
0030         {
0031             MyPaintCurveRangeModel::NormalizedCurve normalized;
0032             QList<QPointF> points = KisCubicCurve(std::get<0>(curveData)).points();
0033             const QRectF bounds = std::get<1>(curveData);
0034 
0035             normalized.yLimit = qMax(qAbs(bounds.top()), qAbs(bounds.bottom()));
0036             normalized.xMax = bounds.right();
0037             normalized.xMin = bounds.left();
0038             
0039             if (qFuzzyIsNull(normalized.yLimit)) {
0040                 points = {{0.0,0.5}, {1.0, 0.5}};
0041             } else {
0042                 for (auto it = points.begin(); it != points.end(); ++it) {
0043                     it->rx() = (it->x() - bounds.left()) / bounds.width();
0044                     it->ry() = it->y() / (2.0 * normalized.yLimit) + 0.5;
0045                 }
0046             }
0047             
0048             normalized.curve = KisCubicCurve(points).toString();
0049 
0050             //qDebug() << "get" << std::get<0>(curveData) << "->" << normalized.curve << bounds;
0051             return normalized;
0052         },
0053         [] (std::tuple<QString, QRectF> curveData, const MyPaintCurveRangeModel::NormalizedCurve &normalizedCurve) {
0054             QList<QPointF> points = KisCubicCurve(normalizedCurve.curve).points();
0055 
0056             for (auto it = points.begin(); it != points.end(); ++it) {
0057                 it->rx() = it->x() * (normalizedCurve.xMax - normalizedCurve.xMin) + normalizedCurve.xMin;
0058                 it->ry() = (it->y() - 0.5) * normalizedCurve.yLimit * 2.0;
0059             }
0060 
0061             std::get<0>(curveData) = KisCubicCurve(points).toString();
0062 
0063             std::get<1>(curveData) = QRectF(normalizedCurve.xMin,
0064                                             -normalizedCurve.yLimit,
0065                                             normalizedCurve.xMax - normalizedCurve.xMin,
0066                                             2.0 * normalizedCurve.yLimit);
0067 
0068             //qDebug() << "set" << std::get<0>(curveData) << "<-" << normalizedCurve.curve << std::get<1>(curveData);
0069             return curveData;
0070         }
0071     );
0072 
0073 } // namespace
0074 
0075 
0076 using KisWidgetConnectionUtils::ToSpinBoxState;
0077 
0078 MyPaintCurveRangeModel::MyPaintCurveRangeModel(lager::cursor<QString> curve,
0079                                                lager::cursor<QRectF> curveRange,
0080                                                lager::reader<QString> activeSensorId,
0081                                                lager::reader<int> activeSensorLength,
0082                                                qreal maxYRange,
0083                                                const QString &yValueSuffix)
0084     : m_curve(std::move(curve))
0085     , m_curveRange(std::move(curveRange))
0086     , m_activeSensorId(std::move(activeSensorId))
0087     , m_activeSensorLength(std::move(activeSensorLength))
0088     , m_normalizedCurve(lager::with(m_curve, m_curveRange).zoom(curveToNormalizedCurve))
0089     , m_maxYRange(maxYRange)
0090     , m_yValueSuffix(yValueSuffix)
0091     , LAGER_QT(yLimit) {m_normalizedCurve[&NormalizedCurve::yLimit]}
0092     , LAGER_QT(xMin) {m_normalizedCurve[&NormalizedCurve::xMin]}
0093     , LAGER_QT(xMax) {m_normalizedCurve[&NormalizedCurve::xMax]}
0094     , LAGER_QT(xMinState) {lager::with(m_normalizedCurve[&NormalizedCurve::xMin],
0095                                       m_activeSensorId.map(&KisCurveRangeModel::calcXMinValueWithFactory),
0096                                       lager::make_constant(0.0),
0097                                       lager::make_constant(true))
0098                               .map(ToSpinBoxState{})}
0099     , LAGER_QT(xMaxState) {lager::with(m_normalizedCurve[&NormalizedCurve::xMax],
0100                                       lager::make_constant(1.0),
0101                                       lager::with(m_activeSensorId, m_activeSensorLength)
0102                                           .map(&KisCurveRangeModel::calcXMaxValueWithFactory),
0103                                       lager::make_constant(true))
0104                               .map(ToSpinBoxState{})}
0105 {
0106 
0107 }
0108 
0109 MyPaintCurveRangeModel::~MyPaintCurveRangeModel()
0110 {
0111 
0112 }
0113 
0114 KisCurveRangeModelFactory MyPaintCurveRangeModel::factory(qreal maxYRange, const QString &yValueSuffix)
0115 {
0116     return
0117         [maxYRange, yValueSuffix](lager::cursor<QString> curve, lager::cursor<QRectF> curveRange, lager::reader<QString> activeSensorId, lager::reader<int> activeSensorLength) {
0118             return new MyPaintCurveRangeModel(curve, curveRange, activeSensorId, activeSensorLength, maxYRange, yValueSuffix);
0119             };
0120 }
0121 
0122 std::tuple<QString, QRectF> MyPaintCurveRangeModel::reshapeCurve(std::tuple<QString, QRectF> curve)
0123 {
0124     /**
0125      * Krita's GUI doesn't support x-range more narrow than 0...1, so
0126      * we should extend it if necessary
0127      */
0128     std::get<1>(curve) |= QRect(0, -1, 1, 2);
0129 
0130     NormalizedCurve normalized = lager::view(curveToNormalizedCurve, curve);
0131     curve = lager::set(curveToNormalizedCurve, curve, normalized);
0132     return curve;
0133 }
0134 
0135 lager::cursor<QString> MyPaintCurveRangeModel::curve()
0136 {
0137     return m_normalizedCurve[&NormalizedCurve::curve];
0138 }
0139 
0140 lager::reader<QString> MyPaintCurveRangeModel::xMinLabel()
0141 {
0142     return m_normalizedCurve[&NormalizedCurve::xMin].map(formatQRealAsString);
0143 }
0144 
0145 lager::reader<QString> MyPaintCurveRangeModel::xMaxLabel()
0146 {
0147     return m_normalizedCurve[&NormalizedCurve::xMax].map(formatQRealAsString);
0148 }
0149 
0150 lager::reader<QString> MyPaintCurveRangeModel::yMinLabel()
0151 {
0152     return yMinValue().map(formatQRealAsStringWithSuffix(m_yValueSuffix));
0153 }
0154 
0155 lager::reader<QString> MyPaintCurveRangeModel::yMaxLabel()
0156 {
0157     return yMaxValue().map(formatQRealAsStringWithSuffix(m_yValueSuffix));
0158 }
0159 
0160 lager::reader<qreal> MyPaintCurveRangeModel::yMinValue()
0161 {
0162     return m_normalizedCurve[&NormalizedCurve::yLimit].xform(kiszug::map_mupliply<qreal>(-1.0));
0163 }
0164 
0165 lager::reader<qreal> MyPaintCurveRangeModel::yMaxValue()
0166 {
0167     return m_normalizedCurve[&NormalizedCurve::yLimit];
0168 }
0169 
0170 lager::reader<QString> MyPaintCurveRangeModel::yValueSuffix()
0171 {
0172     return lager::make_constant(m_yValueSuffix);
0173 }
0174 
0175 lager::reader<qreal> MyPaintCurveRangeModel::xMinValue()
0176 {
0177     return m_normalizedCurve[&NormalizedCurve::xMin];
0178 }
0179 
0180 lager::reader<qreal> MyPaintCurveRangeModel::xMaxValue()
0181 {
0182     return m_normalizedCurve[&NormalizedCurve::xMax];
0183 }
0184 
0185 lager::reader<QString> MyPaintCurveRangeModel::xValueSuffix()
0186 {
0187     return lager::make_constant(QString());
0188 }
0189 
0190 qreal MyPaintCurveRangeModel::maxYRange() const
0191 {
0192     return m_maxYRange;
0193 }