File indexing completed on 2024-05-12 15:58:12

0001 /*
0002  *  SPDX-FileCopyrightText: 2004, 2007-2009 Cyrille Berger <cberger@cberger.net>
0003  *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
0004  *  SPDX-FileCopyrightText: 2012 Sven Langkamp <sven.langkamp@gmail.com>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <cmath>
0010 
0011 #include <QDomDocument>
0012 
0013 #include "kis_fast_math.h"
0014 #include "kis_circle_mask_generator.h"
0015 #include "kis_circle_mask_generator_p.h"
0016 #include "kis_base_mask_generator.h"
0017 #include "kis_brush_mask_applicator_factories.h"
0018 #include "kis_brush_mask_applicator_base.h"
0019 
0020 
0021 KisCircleMaskGenerator::KisCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges)
0022     : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, DefaultId),
0023       d(new Private)
0024 {
0025     setScale(1.0, 1.0);
0026 
0027     // store the variable locally to allow vector implementation read it easily
0028     d->copyOfAntialiasEdges = antialiasEdges;
0029 
0030     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCircleMaskGenerator> >(this));
0031 }
0032 
0033 KisCircleMaskGenerator::KisCircleMaskGenerator(const KisCircleMaskGenerator &rhs)
0034     : KisMaskGenerator(rhs),
0035       d(new Private(*rhs.d))
0036 {
0037     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCircleMaskGenerator> >(this));
0038 }
0039 
0040 KisMaskGenerator* KisCircleMaskGenerator::clone() const
0041 {
0042     return new KisCircleMaskGenerator(*this);
0043 }
0044 
0045 void KisCircleMaskGenerator::setScale(qreal scaleX, qreal scaleY)
0046 {
0047     KisMaskGenerator::setScale(scaleX, scaleY);
0048 
0049     d->xcoef = 2.0 / effectiveSrcWidth();
0050     d->ycoef = 2.0 / effectiveSrcHeight();
0051     d->xfadecoef = qFuzzyCompare(horizontalFade(), 0) ? 1 : (2.0 / (horizontalFade() * effectiveSrcWidth()));
0052     d->yfadecoef = qFuzzyCompare(verticalFade()  , 0) ? 1 : (2.0 / (verticalFade() * effectiveSrcHeight()));
0053     d->transformedFadeX = d->xfadecoef * d->safeSoftnessCoeff;
0054     d->transformedFadeY = d->yfadecoef * d->safeSoftnessCoeff;
0055 }
0056 
0057 KisCircleMaskGenerator::~KisCircleMaskGenerator()
0058 {
0059 }
0060 
0061 bool KisCircleMaskGenerator::shouldVectorize() const
0062 {
0063     return !shouldSupersample() && spikes() == 2;
0064 }
0065 
0066 KisBrushMaskApplicatorBase* KisCircleMaskGenerator::applicator()
0067 {
0068     return d->applicator.data();
0069 }
0070 
0071 quint8 KisCircleMaskGenerator::valueAt(qreal x, qreal y) const
0072 {
0073     if (isEmpty()) return 255;
0074     qreal xr = (x /*- m_xcenter*/);
0075     qreal yr = qAbs(y /*- m_ycenter*/);
0076     fixRotation(xr, yr);
0077 
0078     qreal n = norme(xr * d->xcoef, yr * d->ycoef);
0079     if (n > 1.0) return 255;
0080 
0081     // we add +1.0 to ensure correct antialiasing on the border
0082     if (antialiasEdges()) {
0083         xr = qAbs(xr) + 1.0;
0084         yr = qAbs(yr) + 1.0;
0085     }
0086 
0087     qreal nf = norme(xr * d->transformedFadeX,
0088                      yr * d->transformedFadeY);
0089 
0090     if (nf < 1.0) return 0;
0091     return 255 * n * (nf - 1.0) / (nf - n);
0092 }
0093 
0094 void KisCircleMaskGenerator::setSoftness(qreal softness)
0095 {
0096     KisMaskGenerator::setSoftness(softness);
0097     d->safeSoftnessCoeff = qreal(1.0) / qMax(qreal(0.01), softness);
0098 
0099     d->transformedFadeX = d->xfadecoef * d->safeSoftnessCoeff;
0100     d->transformedFadeY = d->yfadecoef * d->safeSoftnessCoeff;
0101 }
0102 
0103 void KisCircleMaskGenerator::resetMaskApplicator(bool forceScalar)
0104 {
0105     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisCircleMaskGenerator> >(this,forceScalar));
0106 }