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 <kis_fast_math.h>
0014 #include "kis_antialiasing_fade_maker.h"
0015 #include "kis_brush_mask_applicator_factories.h"
0016 #include "kis_brush_mask_applicator_base.h"
0017 
0018 #include "kis_curve_rect_mask_generator.h"
0019 #include "kis_curve_rect_mask_generator_p.h"
0020 #include "kis_curve_circle_mask_generator.h"
0021 #include "kis_cubic_curve.h"
0022 
0023 
0024 KisCurveRectangleMaskGenerator::KisCurveRectangleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, const KisCubicCurve &curve, bool antialiasEdges)
0025     : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, RECTANGLE, SoftId), d(new Private(antialiasEdges))
0026 {
0027     d->curveResolution = qRound( qMax(width(),height()) * OVERSAMPLING);
0028     d->curveData = curve.floatTransfer( d->curveResolution + 1);
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<KisCurveRectangleMaskGenerator>>(this));
0036 }
0037 
0038 KisCurveRectangleMaskGenerator::KisCurveRectangleMaskGenerator(const KisCurveRectangleMaskGenerator &rhs)
0039     : KisMaskGenerator(rhs),
0040       d(new Private(*rhs.d))
0041 {
0042     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveRectangleMaskGenerator>>(this));
0043 }
0044 
0045 KisMaskGenerator* KisCurveRectangleMaskGenerator::clone() const
0046 {
0047     return new KisCurveRectangleMaskGenerator(*this);
0048 }
0049 
0050 void KisCurveRectangleMaskGenerator::setScale(qreal scaleX, qreal scaleY)
0051 {
0052     KisMaskGenerator::setScale(scaleX, scaleY);
0053 
0054     qreal halfWidth = 0.5 * effectiveSrcWidth();
0055     qreal halfHeight = 0.5 * effectiveSrcHeight();
0056 
0057     d->xcoeff = 1.0 / halfWidth;
0058     d->ycoeff = 1.0 / halfHeight;
0059 
0060     d->fadeMaker.setLimits(halfWidth, halfHeight);
0061 }
0062 
0063 KisCurveRectangleMaskGenerator::~KisCurveRectangleMaskGenerator()
0064 {
0065 }
0066 
0067 quint8 KisCurveRectangleMaskGenerator::Private::value(qreal xr, qreal yr) const
0068 {
0069     xr = qAbs(xr) * xcoeff;
0070     yr = qAbs(yr) * ycoeff;
0071 
0072     int sIndex = qRound(xr * (curveResolution));
0073     int tIndex = qRound(yr * (curveResolution));
0074 
0075     int sIndexInverted = curveResolution - sIndex;
0076     int tIndexInverted = curveResolution - tIndex;
0077 
0078     qreal blend = (curveData.at(sIndex) * (1.0 - curveData.at(sIndexInverted)) *
0079                    curveData.at(tIndex) * (1.0 - curveData.at(tIndexInverted)));
0080 
0081     return (1.0 - blend) * 255;
0082 }
0083 
0084 quint8 KisCurveRectangleMaskGenerator::valueAt(qreal x, qreal y) const
0085 {
0086     if (isEmpty()) return 255;
0087     qreal xr = x;
0088     qreal yr = qAbs(y);
0089     fixRotation(xr, yr);
0090 
0091     quint8 value;
0092     if (d->fadeMaker.needFade(xr, yr, &value)) {
0093         return value;
0094     }
0095 
0096     return d->value(xr, yr);
0097 }
0098 
0099 void KisCurveRectangleMaskGenerator::toXML(QDomDocument& doc, QDomElement& e) const
0100 {
0101     KisMaskGenerator::toXML(doc, e);
0102     e.setAttribute("softness_curve", curveString());
0103 }
0104 
0105 void KisCurveRectangleMaskGenerator::setSoftness(qreal softness)
0106 {
0107     // performance
0108     if (!d->dirty && softness == 1.0) return;
0109     d->dirty = true;
0110     KisMaskGenerator::setSoftness(softness);
0111     KisCurveCircleMaskGenerator::transformCurveForSoftness(softness,d->curvePoints, d->curveResolution + 1, d->curveData);
0112     d->dirty = false;
0113 }
0114 
0115 bool KisCurveRectangleMaskGenerator::shouldVectorize() const
0116 {
0117     return !shouldSupersample() && spikes() == 2;
0118 }
0119 
0120 KisBrushMaskApplicatorBase* KisCurveRectangleMaskGenerator::applicator()
0121 {
0122     return d->applicator.data();
0123 }
0124 
0125 void KisCurveRectangleMaskGenerator::resetMaskApplicator(bool forceScalar)
0126 {
0127     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCurveRectangleMaskGenerator>>(this,forceScalar));
0128 }
0129