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

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
0003  *  SPDX-FileCopyrightText: 2011 Geoffry Song <goffrie@gmail.com>
0004  *  SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <cmath>
0010 #include <algorithm>
0011 
0012 
0013 #include <QDomDocument>
0014 #include <QVector>
0015 #include <QPointF>
0016 
0017 #include <KoColorSpaceConstants.h>
0018 
0019 #include "kis_fast_math.h"
0020 
0021 #include "kis_base_mask_generator.h"
0022 #include "kis_antialiasing_fade_maker.h"
0023 #include "kis_brush_mask_applicator_factories.h"
0024 #include "kis_brush_mask_applicator_base.h"
0025 #include "kis_gauss_rect_mask_generator.h"
0026 #include "kis_gauss_rect_mask_generator_p.h"
0027 
0028 #define M_SQRT_2 1.41421356237309504880
0029 
0030 #ifdef Q_OS_WIN
0031 // on windows we get our erf() from boost
0032 #include <boost/math/special_functions/erf.hpp>
0033 #define erf(x) boost::math::erf(x)
0034 #endif
0035 
0036 
0037 
0038 KisGaussRectangleMaskGenerator::KisGaussRectangleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges)
0039     : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, RECTANGLE, GaussId), d(new Private(antialiasEdges))
0040 {
0041     setScale(1.0, 1.0);
0042 
0043     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussRectangleMaskGenerator>>(this));
0044 }
0045 
0046 KisGaussRectangleMaskGenerator::KisGaussRectangleMaskGenerator(const KisGaussRectangleMaskGenerator &rhs)
0047     : KisMaskGenerator(rhs),
0048       d(new Private(*rhs.d))
0049 {
0050     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussRectangleMaskGenerator>>(this));
0051 }
0052 
0053 KisMaskGenerator* KisGaussRectangleMaskGenerator::clone() const
0054 {
0055     return new KisGaussRectangleMaskGenerator(*this);
0056 }
0057 
0058 void KisGaussRectangleMaskGenerator::setScale(qreal scaleX, qreal scaleY)
0059 {
0060     KisMaskGenerator::setScale(scaleX, scaleY);
0061 
0062     qreal width = effectiveSrcWidth();
0063     qreal height = effectiveSrcHeight();
0064 
0065     qreal xfade = (1.0 - horizontalFade()/2.0) * width * 0.1;
0066     qreal yfade = (1.0 - verticalFade()/2.0) * height * 0.1;
0067     d->xfade = 1.0 / (M_SQRT_2 * xfade);
0068     d->yfade = 1.0 / (M_SQRT_2 * yfade);
0069     d->halfWidth = width * 0.5 - 2.5 * xfade;
0070     d->halfHeight = height * 0.5 - 2.5 * yfade;
0071     d->alphafactor = 255.0 / (4.0 * erf(d->halfWidth * d->xfade) * erf(d->halfHeight * d->yfade));
0072 
0073     if (std::isnan(d->alphafactor)) d->alphafactor = 0.0f; // erf can return nan if ratio is 0
0074 
0075     d->fadeMaker.setLimits(0.5 * width, 0.5 * height);
0076 }
0077 
0078 KisGaussRectangleMaskGenerator::~KisGaussRectangleMaskGenerator()
0079 {
0080 }
0081 
0082 inline quint8 KisGaussRectangleMaskGenerator::Private::value(qreal xr, qreal yr) const
0083 {
0084     return (quint8) 255 - (quint8) (alphafactor * (erf((halfWidth + xr) * xfade) + erf((halfWidth - xr) * xfade))
0085                                     * (erf((halfHeight + yr) * yfade) + erf((halfHeight - yr) * yfade)));
0086 }
0087 
0088 quint8 KisGaussRectangleMaskGenerator::valueAt(qreal x, qreal y) const
0089 {
0090     if (isEmpty()) return 255;
0091     qreal xr = x;
0092     qreal yr = qAbs(y);
0093     fixRotation(xr, yr);
0094 
0095     quint8 value;
0096     if (d->fadeMaker.needFade(xr, yr, &value)) {
0097         return value;
0098     }
0099 
0100     return d->value(xr, yr);
0101 }
0102 
0103 bool KisGaussRectangleMaskGenerator::shouldVectorize() const
0104 {
0105     return !shouldSupersample() && spikes() == 2;
0106 }
0107 
0108 KisBrushMaskApplicatorBase* KisGaussRectangleMaskGenerator::applicator()
0109 {
0110     return d->applicator.data();
0111 }
0112 
0113 void KisGaussRectangleMaskGenerator::resetMaskApplicator(bool forceScalar)
0114 {
0115     d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussRectangleMaskGenerator>>(this,forceScalar));
0116 }