File indexing completed on 2024-05-12 15:58:14
0001 /* 0002 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <cmath> 0008 0009 #include <QDomDocument> 0010 #include <QVector> 0011 #include <QPointF> 0012 0013 #include <KoColorSpaceConstants.h> 0014 0015 #include "kis_antialiasing_fade_maker.h" 0016 #include "kis_brush_mask_applicator_factories.h" 0017 0018 #include "kis_curve_circle_mask_generator.h" 0019 #include "kis_curve_circle_mask_generator_p.h" 0020 #include "kis_cubic_curve.h" 0021 0022 0023 KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve &curve, bool antialiasEdges) 0024 : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, SoftId), d(new Private(antialiasEdges)) 0025 { 0026 // here we set resolution for the maximum size of the brush! 0027 d->curveResolution = qRound(qMax(width(), height()) * OVERSAMPLING); 0028 d->curveData = curve.floatTransfer(d->curveResolution + 2); 0029 d->curvePoints = curve.points(); 0030 setCurveString(curve.toString()); 0031 d->dirty = false; 0032 0033 setScale(1.0, 1.0); 0034 0035 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator> >(this)); 0036 } 0037 0038 KisCurveCircleMaskGenerator::KisCurveCircleMaskGenerator(const KisCurveCircleMaskGenerator &rhs) 0039 : KisMaskGenerator(rhs), 0040 d(new Private(*rhs.d)) 0041 { 0042 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator> >(this)); 0043 } 0044 0045 KisCurveCircleMaskGenerator::~KisCurveCircleMaskGenerator() 0046 { 0047 } 0048 0049 KisMaskGenerator* KisCurveCircleMaskGenerator::clone() const 0050 { 0051 return new KisCurveCircleMaskGenerator(*this); 0052 } 0053 0054 void KisCurveCircleMaskGenerator::setScale(qreal scaleX, qreal scaleY) 0055 { 0056 KisMaskGenerator::setScale(scaleX, scaleY); 0057 0058 qreal width = effectiveSrcWidth(); 0059 qreal height = effectiveSrcHeight(); 0060 0061 d->xcoef = 2.0 / width; 0062 d->ycoef = 2.0 / height; 0063 0064 d->fadeMaker.setSquareNormCoeffs(d->xcoef, d->ycoef); 0065 } 0066 0067 bool KisCurveCircleMaskGenerator::shouldVectorize() const 0068 { 0069 return !shouldSupersample() && spikes() == 2; 0070 } 0071 0072 KisBrushMaskApplicatorBase* KisCurveCircleMaskGenerator::applicator() 0073 { 0074 return d->applicator.data(); 0075 } 0076 0077 inline quint8 KisCurveCircleMaskGenerator::Private::value(qreal dist) const 0078 { 0079 qreal distance = dist * curveResolution; 0080 0081 quint16 alphaValue = distance; 0082 qreal alphaValueF = distance - alphaValue; 0083 0084 qreal alpha = ( 0085 (1.0 - alphaValueF) * curveData.at(alphaValue) + 0086 alphaValueF * curveData.at(alphaValue+1)); 0087 0088 return (1.0 - alpha) * 255; 0089 } 0090 0091 quint8 KisCurveCircleMaskGenerator::valueAt(qreal x, qreal y) const 0092 { 0093 if (isEmpty()) return 255; 0094 qreal xr = x; 0095 qreal yr = qAbs(y); 0096 fixRotation(xr, yr); 0097 0098 qreal dist = norme(xr * d->xcoef, yr * d->ycoef); 0099 0100 quint8 value; 0101 if (d->fadeMaker.needFade(dist, &value)) { 0102 return value; 0103 } 0104 0105 return d->value(dist); 0106 } 0107 0108 void KisCurveCircleMaskGenerator::toXML(QDomDocument& doc, QDomElement& e) const 0109 { 0110 KisMaskGenerator::toXML(doc, e); 0111 e.setAttribute("softness_curve", curveString()); 0112 } 0113 0114 void KisCurveCircleMaskGenerator::setSoftness(qreal softness) 0115 { 0116 // performance 0117 if (!d->dirty && softness == 1.0) return; 0118 0119 d->dirty = true; 0120 KisMaskGenerator::setSoftness(softness); 0121 KisCurveCircleMaskGenerator::transformCurveForSoftness(softness,d->curvePoints, d->curveResolution+2, d->curveData); 0122 d->dirty = false; 0123 } 0124 0125 void KisCurveCircleMaskGenerator::transformCurveForSoftness(qreal softness,const QList<QPointF> &points, int curveResolution, QVector< qreal >& result) 0126 { 0127 QList<QPointF> newList = points; 0128 newList.detach(); 0129 0130 int size = newList.size(); 0131 if (size == 2){ 0132 // make place for new point in the centre 0133 newList.append(newList.at(1)); 0134 newList[1] = (newList.at(0) + newList.at(2)) * 0.5; 0135 // transoform it 0136 newList[1].setY(qBound<qreal>(0.0,newList.at(1).y() * softness,1.0)); 0137 }else{ 0138 // transform all points except first and last 0139 for (int i = 1; i < size-1; i++){ 0140 newList[i].setY(qBound<qreal>(0.0,newList.at(i).y() * softness,1.0)); 0141 } 0142 } 0143 0144 // compute the data 0145 KisCubicCurve curve(newList); 0146 result = curve.floatTransfer( curveResolution ); 0147 } 0148 0149 void KisCurveCircleMaskGenerator::resetMaskApplicator(bool forceScalar) 0150 { 0151 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveCircleMaskGenerator> >(this,forceScalar)); 0152 }