Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_base_mask_generator.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2004, 2007-2009 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
4 * SPDX-FileCopyrightText: 2011 Sven Langkamp <sven.langkamp@gmail.com>
5 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
11
13#include "kis_mask_generator.h"
15
16#include <cmath>
17#include "kis_fast_math.h"
18
19#include <QDomDocument>
20
25#include "kis_cubic_curve.h"
28#include <kis_dom_utils.h>
29
32 : diameter(1.0),
33 ratio(1.0),
34 softness(1.0),
35 fh(1.0),
36 fv(1.0),
37 cs(0.0),
38 ss(0.0),
40 spikes(2),
41 empty(true),
42 antialiasEdges(false),
43 type(CIRCLE),
44 scaleX(1.0),
45 scaleY(1.0)
46 {
47 }
48
49 Private(const Private &rhs)
50 : diameter(rhs.diameter),
51 ratio(rhs.ratio),
52 softness(rhs.softness),
53 fh(rhs.fh),
54 fv(rhs.fv),
55 cs(rhs.cs),
56 ss(rhs.ss),
58 spikes(rhs.spikes),
59 empty(rhs.empty),
61 type(rhs.type),
63 scaleX(rhs.scaleX),
64 scaleY(rhs.scaleY)
65 {
66 }
67
69 qreal softness;
70 qreal fh, fv;
71 qreal cs, ss;
73 int spikes;
74 bool empty;
77 QString curveString;
78 qreal scaleX;
79 qreal scaleY;
80};
81
82
83KisMaskGenerator::KisMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges, Type type, const KoID& id)
84 : d(new Private), m_id(id)
85{
86 d->diameter = diameter;
87 d->ratio = ratio;
88 d->fh = 0.5 * fh;
89 d->fv = 0.5 * fv;
90 d->softness = 1.0; // by default don't change fade/softness/hardness
91 d->spikes = spikes;
92 d->cachedSpikesAngle = M_PI / d->spikes;
93 d->type = type;
94 d->antialiasEdges = antialiasEdges;
95 d->scaleX = 1.0;
96 d->scaleY = 1.0;
97 init();
98}
99
103
105 : d(new Private(*rhs.d)),
106 m_id(rhs.m_id)
107{
108}
109
111{
112 d->cs = cos(- 2 * M_PI / d->spikes);
113 d->ss = sin(- 2 * M_PI / d->spikes);
114 d->empty = (d->ratio == 0.0 || d->diameter == 0.0);
115}
116
118{
119 return antialiasEdges() && (effectiveSrcWidth() < 10 || effectiveSrcHeight() < 10);
120}
121
123{
124 return effectiveSrcWidth() < 1 || effectiveSrcHeight() < 1;
125}
126
128{
129 return false;
130}
131
132
134{
135 return d->empty;
136}
137
138void KisMaskGenerator::toXML(QDomDocument& doc, QDomElement& e) const
139{
140 Q_UNUSED(doc);
141 //e.setAttribute("radius", d->radius);
142 e.setAttribute("diameter", QString::number(d->diameter));
143 e.setAttribute("ratio", QString::number(d->ratio));
144 e.setAttribute("hfade", QString::number(horizontalFade()));
145 e.setAttribute("vfade", QString::number(verticalFade()));
146 e.setAttribute("spikes", d->spikes);
147 e.setAttribute("type", d->type == CIRCLE ? "circle" : "rect");
148 e.setAttribute("antialiasEdges", d->antialiasEdges);
149 e.setAttribute("id", id());
150}
151
153{
154 double diameter = 1.0;
155 // backward compatibility -- it was mistakenly named radius for 2.2
156 if (elt.hasAttribute("radius")){
157 diameter = KisDomUtils::toDouble(elt.attribute("radius", "1.0"));
158 }
159 else /*if (elt.hasAttribute("diameter"))*/{
160 diameter = KisDomUtils::toDouble(elt.attribute("diameter", "1.0"));
161 }
162 double ratio = KisDomUtils::toDouble(elt.attribute("ratio", "1.0"));
163 double hfade = KisDomUtils::toDouble(elt.attribute("hfade", "0.0"));
164 double vfade = KisDomUtils::toDouble(elt.attribute("vfade", "0.0"));
165
166 int spikes = elt.attribute("spikes", "2").toInt();
167 QString typeShape = elt.attribute("type", "circle");
168 QString id = elt.attribute("id", DefaultId.id());
169 bool antialiasEdges = elt.attribute("antialiasEdges", "0").toInt();
170
171 if (id == DefaultId.id()) {
172 if (typeShape == "circle") {
173 return new KisCircleMaskGenerator(diameter, ratio, hfade, vfade, spikes, antialiasEdges);
174 } else {
175 return new KisRectangleMaskGenerator(diameter, ratio, hfade, vfade, spikes, antialiasEdges);
176 }
177 }
178
179 if (id == SoftId.id()) {
180 const KisCubicCurve curve(elt.attribute("softness_curve","0,0;1,1"));
181
182 if (typeShape == "circle") {
183 return new KisCurveCircleMaskGenerator(diameter, ratio, hfade, vfade, spikes, curve, antialiasEdges);
184 } else {
185 return new KisCurveRectangleMaskGenerator(diameter, ratio, hfade, vfade, spikes, curve, antialiasEdges);
186 }
187 }
188
189 if (id == GaussId.id()) {
190 if (typeShape == "circle") {
192 } else {
194 }
195 }
196
197 // if unknown
198 return new KisCircleMaskGenerator(diameter, ratio, hfade, vfade, spikes, true);
199}
200
202{
203 return d->diameter;
204}
205
207{
208 if (d->spikes == 2) {
209 return d->diameter * d->ratio;
210 }
211 return d->diameter;
212}
213
215{
216 return d->diameter * d->scaleX;
217}
218
220{
226 return d->diameter * d->ratio * d->scaleY;
227}
228
230{
231 return d->diameter;
232}
233
235{
236 d->diameter = value;
237 init();
238 setScale(d->scaleX, d->scaleY);
239}
240
242{
243 return d->ratio;
244}
245
247{
248 return d->softness;
249}
250
251
253{
254 d->softness = softness;
255}
256
257
259{
260 return 2.0 * d->fh; // 'cause in init we divide it again
261}
262
264{
265 return 2.0 * d->fv; // 'cause in init we divide it again
266}
267
269{
270 return d->spikes;
271}
272
274{
275 return d->type;
276}
277
279{
280 QList<KoID> ids;
281 ids << DefaultId << SoftId << GaussId;
282 return ids;
283}
284
286{
287 return d->curveString;
288}
289
290void KisMaskGenerator::setCurveString(const QString& curveString)
291{
292 d->curveString = curveString;
293}
294
296{
297 return d->antialiasEdges;
298}
299
300void KisMaskGenerator::setScale(qreal scaleX, qreal scaleY)
301{
302 d->scaleX = scaleX;
303 d->scaleY = scaleY;
304}
305
306void KisMaskGenerator::fixRotation(qreal &xr, qreal &yr) const
307{
308 if (d->spikes > 2) {
309 double angle = (KisFastMath::atan2(yr, xr));
310
311 while (angle > d->cachedSpikesAngle){
312 double sx = xr;
313 double sy = yr;
314
315 xr = d->cs * sx - d->ss * sy;
316 yr = d->ss * sx + d->cs * sy;
317
318 angle -= 2 * d->cachedSpikesAngle;
319 }
320 }
321}
float value(const T *src, size_t ch)
void setCurveString(const QString &curveString)
virtual void setSoftness(qreal softness)
virtual bool shouldSupersample() const
virtual bool shouldVectorize() const
void setDiameter(qreal value)
virtual void toXML(QDomDocument &, QDomElement &) const
const QScopedPointer< Private > d
void fixRotation(qreal &xr, qreal &yr) const
KisMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int spikes, bool antialiasEdges, Type type, const KoID &id=DefaultId)
virtual void setScale(qreal scaleX, qreal scaleY)
virtual bool shouldSupersample6x6() const
static KisMaskGenerator * fromXML(const QDomElement &)
static QList< KoID > maskGeneratorIds()
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
const KoID SoftId("soft", ki18n("Soft"))
generate brush mask from former softbrush paintop, where softness is based on curve
const KoID DefaultId("default", ki18n("Default"))
generate Krita default mask generator
const KoID GaussId("gauss", ki18n("Gaussian"))
generate brush mask with a Gaussian-blurred edge
#define M_PI
Definition kis_global.h:111
double toDouble(const QString &str, bool *ok=nullptr)
KRITAIMAGE_EXPORT qreal atan2(qreal y, qreal x)
atan2 replacement