File indexing completed on 2025-02-02 04:22:12
0001 /* 0002 * SPDX-FileCopyrightText: 2008 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de> 0004 * SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 #include "KisCurveOption.h" 0009 #include "KisCurveOptionData.h" 0010 #include "kis_algebra_2d.h" 0011 0012 #include <sensors/KisDynamicSensors.h> 0013 #include <sensors/KisDynamicSensorDrawingAngle.h> 0014 #include <sensors/KisDynamicSensorDistance.h> 0015 #include <sensors/KisDynamicSensorFade.h> 0016 #include <sensors/KisDynamicSensorTime.h> 0017 #include <sensors/KisDynamicSensorFuzzy.h> 0018 0019 namespace { 0020 template <typename Sensor, typename Data, typename... Args> 0021 void addSensor(std::vector<std::unique_ptr<KisDynamicSensor>> &sensors, 0022 const Data &data, std::optional<KisCubicCurve> commonCurve, Args... args) 0023 { 0024 if (data.isActive) { 0025 sensors.push_back(std::unique_ptr<KisDynamicSensor>(new Sensor(data, commonCurve, args...))); 0026 } 0027 } 0028 0029 std::vector<std::unique_ptr<KisDynamicSensor>> generateSensors(const KisCurveOptionData &data) 0030 { 0031 std::vector<std::unique_ptr<KisDynamicSensor>> result; 0032 0033 std::optional<KisCubicCurve> commonCurve; 0034 if (data.useSameCurve) { 0035 commonCurve = KisCubicCurve(data.commonCurve); 0036 } 0037 0038 const KisKritaSensorData &sensorStruct = data.sensorStruct(); 0039 0040 addSensor<KisDynamicSensorPressure>(result, sensorStruct.sensorPressure, commonCurve); 0041 addSensor<KisDynamicSensorPressureIn>(result, sensorStruct.sensorPressureIn, commonCurve); 0042 addSensor<KisDynamicSensorTangentialPressure>(result, sensorStruct.sensorTangentialPressure, commonCurve); 0043 addSensor<KisDynamicSensorDrawingAngle>(result, sensorStruct.sensorDrawingAngle, commonCurve); 0044 addSensor<KisDynamicSensorXTilt>(result, sensorStruct.sensorXTilt, commonCurve); 0045 addSensor<KisDynamicSensorYTilt>(result, sensorStruct.sensorYTilt, commonCurve); 0046 addSensor<KisDynamicSensorTiltDirection>(result, sensorStruct.sensorTiltDirection, commonCurve); 0047 addSensor<KisDynamicSensorTiltElevation>(result, sensorStruct.sensorTiltElevation, commonCurve); 0048 addSensor<KisDynamicSensorRotation>(result, sensorStruct.sensorRotation, commonCurve); 0049 addSensor<KisDynamicSensorFuzzyPerDab>(result, sensorStruct.sensorFuzzyPerDab, commonCurve); 0050 addSensor<KisDynamicSensorFuzzyPerStroke>(result, sensorStruct.sensorFuzzyPerStroke, commonCurve, data.id.id()); 0051 addSensor<KisDynamicSensorSpeed>(result, sensorStruct.sensorSpeed, commonCurve); 0052 addSensor<KisDynamicSensorFade>(result, sensorStruct.sensorFade, commonCurve); 0053 addSensor<KisDynamicSensorDistance>(result, sensorStruct.sensorDistance, commonCurve); 0054 addSensor<KisDynamicSensorTime>(result, sensorStruct.sensorTime, commonCurve); 0055 addSensor<KisDynamicSensorPerspective>(result, sensorStruct.sensorPerspective, commonCurve); 0056 0057 return result; 0058 } 0059 } 0060 0061 qreal KisCurveOption::ValueComponents::rotationLikeValue(qreal normalizedBaseAngle, bool absoluteAxesFlipped, qreal scalingPartCoeff, bool disableScalingPart) const { 0062 const qreal offset = 0063 !hasAbsoluteOffset ? normalizedBaseAngle : 0064 absoluteAxesFlipped ? 0.5 - absoluteOffset : 0065 absoluteOffset; 0066 0067 const qreal realScalingPart = hasScaling && !disableScalingPart ? KisDynamicSensor::scalingToAdditive(scaling) : 0.0; 0068 const qreal realAdditivePart = hasAdditive ? additive : 0; 0069 0070 qreal value = KisAlgebra2D::wrapValue(2 * offset + constant * (scalingPartCoeff * realScalingPart + realAdditivePart), -1.0, 1.0); 0071 if (qIsNaN(value)) { 0072 qWarning() << "rotationLikeValue returns NaN!" << normalizedBaseAngle << absoluteAxesFlipped; 0073 value = 0; 0074 } 0075 return value; 0076 } 0077 0078 qreal KisCurveOption::ValueComponents::sizeLikeValue() const { 0079 const qreal offset = 0080 hasAbsoluteOffset ? absoluteOffset : 1.0; 0081 0082 const qreal realScalingPart = hasScaling ? scaling : 1.0; 0083 const qreal realAdditivePart = hasAdditive ? KisDynamicSensor::additiveToScaling(additive) : 1.0; 0084 0085 return qBound(minSizeLikeValue, 0086 constant * offset * realScalingPart * realAdditivePart, 0087 maxSizeLikeValue); 0088 } 0089 0090 0091 KisCurveOption::KisCurveOption(const KisCurveOptionData &data) 0092 : m_isChecked(data.isChecked) 0093 , m_useCurve(data.useCurve) 0094 , m_curveMode(data.curveMode) 0095 , m_strengthValue(data.strengthValue) 0096 , m_strengthMinValue(data.strengthMinValue) 0097 , m_strengthMaxValue(data.strengthMaxValue) 0098 , m_sensors(generateSensors(data)) 0099 { 0100 } 0101 0102 KisCurveOption::ValueComponents KisCurveOption::computeValueComponents(const KisPaintInformation& info, bool useStrengthValue) const 0103 { 0104 ValueComponents components; 0105 0106 if (m_useCurve) { 0107 QList<double> sensorValues; 0108 for (auto i = m_sensors.cbegin(); i != m_sensors.cend(); ++i) { 0109 KisDynamicSensor *s(i->get()); 0110 0111 qreal valueFromCurve = s->parameter(info); 0112 if (s->isAdditive()) { 0113 components.additive += valueFromCurve; 0114 components.hasAdditive = true; 0115 } else if (s->isAbsoluteRotation()) { 0116 components.absoluteOffset = valueFromCurve; 0117 components.hasAbsoluteOffset =true; 0118 } else { 0119 sensorValues << valueFromCurve; 0120 components.hasScaling = true; 0121 } 0122 } 0123 0124 if (sensorValues.count() == 1) { 0125 components.scaling = sensorValues.first(); 0126 } else { 0127 0128 if (m_curveMode == 1){ // add 0129 components.scaling = 0; 0130 double i; 0131 foreach (i, sensorValues) { 0132 components.scaling += i; 0133 } 0134 } else if (m_curveMode == 2){ //max 0135 components.scaling = *std::max_element(sensorValues.begin(), sensorValues.end()); 0136 0137 } else if (m_curveMode == 3){ //min 0138 components.scaling = *std::min_element(sensorValues.begin(), sensorValues.end()); 0139 0140 } else if (m_curveMode == 4){ //difference 0141 double max = *std::max_element(sensorValues.begin(), sensorValues.end()); 0142 double min = *std::min_element(sensorValues.begin(), sensorValues.end()); 0143 components.scaling = max-min; 0144 0145 } else { //multuply - default 0146 double i; 0147 foreach (i, sensorValues) { 0148 components.scaling *= i; 0149 } 0150 } 0151 } 0152 0153 } 0154 0155 if (useStrengthValue) { 0156 components.constant = m_strengthValue; 0157 } 0158 0159 components.minSizeLikeValue = m_strengthMinValue; 0160 components.maxSizeLikeValue = m_strengthMaxValue; 0161 0162 return components; 0163 } 0164 0165 qreal KisCurveOption::computeSizeLikeValue(const KisPaintInformation& info, bool useStrengthValue) const 0166 { 0167 const ValueComponents components = computeValueComponents(info, useStrengthValue); 0168 return components.sizeLikeValue(); 0169 } 0170 0171 qreal KisCurveOption::computeRotationLikeValue(const KisPaintInformation& info, qreal baseValue, bool absoluteAxesFlipped, qreal scalingPartCoeff, bool disableScalingPart) const 0172 { 0173 const ValueComponents components = computeValueComponents(info, true); 0174 return components.rotationLikeValue(baseValue, absoluteAxesFlipped, scalingPartCoeff, disableScalingPart); 0175 } 0176 0177 qreal KisCurveOption::strengthValue() const 0178 { 0179 return m_strengthValue; 0180 } 0181 0182 qreal KisCurveOption::strengthMinValue() const 0183 { 0184 return m_strengthMinValue; 0185 } 0186 0187 qreal KisCurveOption::strengthMaxValue() const 0188 { 0189 return m_strengthMaxValue; 0190 } 0191 0192 bool KisCurveOption::isChecked() const 0193 { 0194 return m_isChecked; 0195 } 0196 0197 bool KisCurveOption::isRandom() const 0198 { 0199 for (auto it = m_sensors.begin(); it != m_sensors.end(); ++it) { 0200 const KisDynamicSensor *sensor = it->get(); 0201 if (sensor->id() == FuzzyPerDabId || sensor->id() == FuzzyPerStrokeId) return true; 0202 } 0203 return false; 0204 }