Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_liquify_paintop.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QPainterPath>
10#include <QTransform>
11
12
15#include "kis_algebra_2d.h"
19
20
29
31 : m_d(new Private(props, worker))
32{
33}
34
38
40 const KisPaintInformation &info)
41{
42 const qreal diameter = props.size();
43 const qreal reverseCoeff = props.reverseDirection() ? -1.0 : 1.0;
44
45 QPainterPath outline;
46 outline.addEllipse(-0.5 * diameter, -0.5 * diameter,
47 diameter, diameter);
48
49 switch (props.mode()) {
53 break;
55 QPainterPath p;
56 p.lineTo(-3.0, 4.0);
57 p.moveTo(0.0, 0.0);
58 p.lineTo(-3.0, -4.0);
59
60 QTransform S;
61 if (diameter < 15.0) {
62 const qreal scale = diameter / 15.0;
63 S = QTransform::fromScale(scale, scale);
64 }
65 QTransform R;
66 R.rotateRadians(-reverseCoeff * 0.5 * M_PI);
67 QTransform T = QTransform::fromTranslate(0.5 * diameter, 0.0);
68
69 p = (S * R * T).map(p);
70 outline.addPath(p);
71
72 break;
73 }
75 qreal normalAngle = info.drawingAngle() + reverseCoeff * 0.5 * M_PI;
76
77 QPainterPath p = KisAlgebra2D::smallArrow();
78
79 const qreal offset = qMax(0.8 * diameter, 15.0);
80
81 QTransform R;
82 R.rotateRadians(normalAngle);
83 QTransform T = QTransform::fromTranslate(offset, 0.0);
84 p = (T * R).map(p);
85
86 outline.addPath(p);
87
88 break;
89 }
91 break;
93 qFatal("Not supported mode");
94 }
95
96 return outline;
97}
98
99// TODO: Reduce code duplication between KisLiquifyPaintop and KisPaintOp. It might be possible to
100// make them both subclasses of some more general base class.
102 KisDistanceInformation &currentDistance) const
103{
104 KisPaintInformation pi(info);
105 KisSpacingInformation spacingInfo;
106 {
108 = pi.registerDistanceInformation(&currentDistance);
109 spacingInfo = updateSpacingImpl(pi);
110 }
111
112 currentDistance.updateSpacing(spacingInfo);
113}
114
116 KisDistanceInformation &currentDistance) const
117{
118 KisPaintInformation pi(info);
119 KisTimingInformation timingInfo;
120 {
122 = pi.registerDistanceInformation(&currentDistance);
123 timingInfo = updateTimingImpl(pi);
124 }
125
126 currentDistance.updateTiming(timingInfo);
127}
128
130{
131 const qreal size = computeSize(pi);
132
133 const qreal spacing = m_d->props.spacing() * size;
134
135 const qreal reverseCoeff =
137 m_d->props.reverseDirection() ? -1.0 : 1.0;
138 const qreal amount = m_d->props.amountHasPressure() ?
139 pi.pressure() * reverseCoeff * m_d->props.amount():
140 reverseCoeff * m_d->props.amount();
141
142 const bool useWashMode = m_d->props.useWashMode();
143 const qreal flow = m_d->props.flow();
144
145 switch (m_d->props.mode()) {
147 const qreal offsetLength = size * amount;
148 m_d->worker->translatePoints(pi.pos(),
149 pi.drawingDirectionVector() * offsetLength,
150 size, useWashMode, flow);
151
152 break;
153 }
155 m_d->worker->scalePoints(pi.pos(),
156 amount,
157 size, useWashMode, flow);
158 break;
160 m_d->worker->rotatePoints(pi.pos(),
161 2.0 * M_PI * amount,
162 size, useWashMode, flow);
163 break;
165 const qreal offsetLength = size * amount;
166 m_d->worker->translatePoints(pi.pos(),
168 size, useWashMode, flow);
169 break;
170 }
172 m_d->worker->undoPoints(pi.pos(),
173 amount,
174 size);
175
176 break;
178 m_d->worker->restoreShapePoints(pi.pos(),
179 amount,
180 size,
181 m_d->props.preserveShapeRotation(),
182 m_d->props.preserveShapeScale(),
183 m_d->props.preserveShapeStretch());
184
185 break;
187 qFatal("Not supported mode");
188 }
189
190 return KisSpacingInformation(spacing);
191}
192
197
199{
200 Q_UNUSED(pi);
201 // Don't use airbrushing.
202 return KisTimingInformation();
203}
204
206{
207 static const qreal sizeToSigmaCoeff = 1.0 / 3.0;
208 return sizeToSigmaCoeff *
209 (m_d->props.sizeHasPressure() ?
210 pi.pressure() * m_d->props.size():
211 m_d->props.size());
212}
Eigen::Matrix< double, 4, 2 > S
const Params2D p
Eigen::Matrix< double, 4, 2 > R
const QScopedPointer< Private > m_d
qreal computeSize(const KisPaintInformation &pi) const
KisSpacingInformation updateSpacingImpl(const KisPaintInformation &pi) const
KisSpacingInformation paintAt(const KisPaintInformation &pi)
static QPainterPath brushOutline(const KisLiquifyProperties &props, const KisPaintInformation &info)
void updateSpacing(const KisPaintInformation &info, KisDistanceInformation &currentDistance) const
KisLiquifyPaintop(const KisLiquifyProperties &props, KisLiquifyTransformWorker *worker)
void updateTiming(const KisPaintInformation &info, KisDistanceInformation &currentDistance) const
KisTimingInformation updateTimingImpl(const KisPaintInformation &pi) const
static bool supportsReverseDirection(LiquifyMode mode)
const QPointF & pos() const
DistanceInformationRegistrar registerDistanceInformation(KisDistanceInformation *distance)
QPointF drawingDirectionVector() const
qreal pressure() const
The pressure of the value (from 0.0 to 1.0)
qreal drawingAngle(bool considerLockedAngle=false) const
#define M_PI
Definition kis_global.h:111
QPainterPath smallArrow()
T rightUnitNormal(const T &a)
void updateTiming(const KisTimingInformation &timing)
void updateSpacing(const KisSpacingInformation &spacing)
Private(const KisLiquifyProperties &_props, KisLiquifyTransformWorker *_worker)
KisLiquifyTransformWorker * worker