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 }