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 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <cmath> 0009 0010 #include <QDomDocument> 0011 #include <QVector> 0012 #include <QPointF> 0013 0014 #include <KoColorSpaceConstants.h> 0015 0016 #include "kis_fast_math.h" 0017 0018 #include "kis_base_mask_generator.h" 0019 #include "kis_antialiasing_fade_maker.h" 0020 #include "kis_brush_mask_applicator_factories.h" 0021 #include "kis_brush_mask_applicator_base.h" 0022 #include "kis_gauss_circle_mask_generator.h" 0023 #include "kis_gauss_circle_mask_generator_p.h" 0024 0025 #define M_SQRT_2 1.41421356237309504880 0026 0027 #ifdef Q_OS_WIN 0028 // on windows we get our erf() from boost 0029 #include <boost/math/special_functions/erf.hpp> 0030 #define erf(x) boost::math::erf(x) 0031 #endif 0032 0033 0034 KisGaussCircleMaskGenerator::KisGaussCircleMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges) 0035 : KisMaskGenerator(diameter, ratio, fh, fv, spikes, antialiasEdges, CIRCLE, GaussId), 0036 d(new Private(antialiasEdges)) 0037 { 0038 d->ycoef = 1.0 / ratio; 0039 d->fade = 1.0 - (fh + fv) / 2.0; 0040 0041 if (d->fade == 0.0) d->fade = 1e-6; 0042 else if (d->fade == 1.0) d->fade = 1.0 - 1e-6; // would become undefined for fade == 0 or 1 0043 0044 d->center = (2.5 * (6761.0*d->fade-10000.0))/(M_SQRT_2*6761.0*d->fade); 0045 d->alphafactor = 255.0 / (2.0 * erf(d->center)); 0046 0047 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussCircleMaskGenerator>>(this)); 0048 0049 } 0050 0051 KisGaussCircleMaskGenerator::KisGaussCircleMaskGenerator(const KisGaussCircleMaskGenerator &rhs) 0052 : KisMaskGenerator(rhs), 0053 d(new Private(*rhs.d)) 0054 { 0055 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussCircleMaskGenerator>>(this)); 0056 } 0057 0058 KisMaskGenerator* KisGaussCircleMaskGenerator::clone() const 0059 { 0060 return new KisGaussCircleMaskGenerator(*this); 0061 } 0062 0063 void KisGaussCircleMaskGenerator::setScale(qreal scaleX, qreal scaleY) 0064 { 0065 KisMaskGenerator::setScale(scaleX, scaleY); 0066 d->ycoef = scaleX / (scaleY * ratio()); 0067 0068 d->distfactor = M_SQRT_2 * 12500.0 / (6761.0 * d->fade * effectiveSrcWidth() / 2.0); 0069 d->fadeMaker.setRadius(0.5 * effectiveSrcWidth()); 0070 } 0071 0072 KisGaussCircleMaskGenerator::~KisGaussCircleMaskGenerator() 0073 { 0074 } 0075 0076 inline quint8 KisGaussCircleMaskGenerator::Private::value(qreal dist) const 0077 { 0078 dist *= distfactor; 0079 quint8 ret = alphafactor * (erf(dist + center) - erf(dist - center)); 0080 return (quint8) 255 - ret; 0081 } 0082 0083 bool KisGaussCircleMaskGenerator::shouldVectorize() const 0084 { 0085 return !shouldSupersample() && spikes() == 2; 0086 } 0087 0088 KisBrushMaskApplicatorBase* KisGaussCircleMaskGenerator::applicator() 0089 { 0090 return d->applicator.data(); 0091 } 0092 0093 quint8 KisGaussCircleMaskGenerator::valueAt(qreal x, qreal y) const 0094 { 0095 if (isEmpty()) return 255; 0096 qreal xr = x; 0097 qreal yr = qAbs(y); 0098 fixRotation(xr, yr); 0099 0100 qreal dist = sqrt(norme(xr, yr * d->ycoef)); 0101 0102 quint8 value; 0103 if (d->fadeMaker.needFade(dist, &value)) { 0104 return value; 0105 } 0106 0107 return d->value(dist); 0108 } 0109 0110 void KisGaussCircleMaskGenerator::resetMaskApplicator(bool forceScalar) 0111 { 0112 d->applicator.reset(createOptimizedClass<MaskApplicatorFactory<KisGaussCircleMaskGenerator>>(this,forceScalar)); 0113 }