Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_dyna.cpp
Go to the documentation of this file.
1/*
2 * kis_tool_dyna.cpp - part of Krita
3 *
4 * SPDX-FileCopyrightText: 2009-2011 Lukáš Tvrdý <LukasT.dev@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kis_tool_dyna.h"
10
11#include <QCheckBox>
12#include <QDoubleSpinBox>
13#include <QLabel>
14
15#include <klocalizedstring.h>
16#include <ksharedconfig.h>
17
18#include "KoPointerEvent.h"
19#include "kundo2magicstring.h"
20
21#include "kis_cursor.h"
22#include <kis_slider_spin_box.h>
23#include <KisAngleSelector.h>
24
25
26#define MAXIMUM_SMOOTHNESS 1000
27#define MAXIMUM_MAGNETISM 1000
28
29#define MIN_MASS 1.0
30#define MAX_MASS 160.0
31#define MIN_DRAG 0.0
32#define MAX_DRAG 0.5
33#define MIN_ACC 0.000001
34#define MIN_VEL 0.000001
35
36
38 : KisToolFreehand(canvas, KisCursor::load("tool_freehand_cursor.xpm", 2, 2), kundo2_i18n("Dynamic Brush Stroke"), false)
39{
40 setObjectName("tool_dyna");
42 initDyna();
43}
44
45
47{
48 /* dynadraw init */
49 m_curmass = 0.5;
50 m_curdrag = 0.15;
51 m_mouse.fixedangle = false;
52 m_width = 1.5;
53 m_xangle = 0.60;
54 m_yangle = 0.20;
55 m_widthRange = 0.05;
56}
57
58
62
69
70void KisToolDyna::activate(const QSet<KoShape*> &shapes)
71{
73 m_configGroup = KSharedConfig::openConfig()->group(toolId());
74}
75
77{
78 QRectF imageSize = QRectF(QPointF(0.0,0.0),currentImage()->size());
79 QRectF documentSize = currentImage()->pixelToDocument(imageSize);
80 m_surfaceWidth = documentSize.width();
81 m_surfaceHeight = documentSize.height();
82 setMousePosition(event->point);
84
86}
87
97
99{
100 setMousePosition(event->point);
101
102 if (applyFilter(m_mousePos.x(), m_mousePos.y())) {
103 KoPointerEvent newEvent = filterEvent(event);
105 }
106}
107
108// dyna algorithm
109int KisToolDyna::applyFilter(qreal mx, qreal my)
110{
111 /* calculate mass and drag */
112 qreal mass = flerp(MIN_MASS, MAX_MASS, m_curmass);
113 qreal drag = flerp(MIN_DRAG, MAX_DRAG, m_curdrag * m_curdrag);
114
115 /* calculate force and acceleration */
116 qreal fx = mx - m_mouse.curx;
117 qreal fy = my - m_mouse.cury;
118
119 m_mouse.acc = sqrt(fx * fx + fy * fy);
120
121 if (m_mouse.acc < MIN_ACC) {
122 return 0;
123 }
124
125 m_mouse.accx = fx / mass;
126 m_mouse.accy = fy / mass;
127
128 /* calculate new velocity */
134 if (m_mouse.vel < MIN_VEL) {
135 return 0;
136 }
137
138 /* calculate angle of drawing tool */
139 if (m_mouse.fixedangle) {
142 } else {
145 }
146
147 m_mouse.velx = m_mouse.velx * (1.0 - drag);
148 m_mouse.vely = m_mouse.vely * (1.0 - drag);
149
154
155 return 1;
156}
157
158
160{
161 qreal wid = m_widthRange - m_mouse.vel;
162
163 wid = wid * m_width;
164
165 if (wid < 0.00001) {
166 wid = 0.00001;
167 }
168
169 qreal delx = m_mouse.angx * wid;
170 qreal dely = m_mouse.angy * wid;
171
172 qreal px = m_mouse.lastx;
173 qreal py = m_mouse.lasty;
174 qreal nx = m_mouse.curx;
175 qreal ny = m_mouse.cury;
176
177 QPointF prev(px , py); // previous position
178 QPointF now(nx , ny); // new position
179
180 QPointF prevr(px + m_odelx , py + m_odely);
181 QPointF prevl(px - m_odelx , py - m_odely);
182
183 QPointF nowl(nx - delx , ny - dely);
184 QPointF nowr(nx + delx , ny + dely);
185
186 // transform coords from float points into image points
187 prev.rx() *= m_surfaceWidth;
188 prevr.rx() *= m_surfaceWidth;
189 prevl.rx() *= m_surfaceWidth;
190 now.rx() *= m_surfaceWidth;
191 nowl.rx() *= m_surfaceWidth;
192 nowr.rx() *= m_surfaceWidth;
193
194 prev.ry() *= m_surfaceHeight;
195 prevr.ry() *= m_surfaceHeight;
196 prevl.ry() *= m_surfaceHeight;
197 now.ry() *= m_surfaceHeight;
198 nowl.ry() *= m_surfaceHeight;
199 nowr.ry() *= m_surfaceHeight;
200
201#if 0
202
203 qreal xTilt, yTilt;
204 qreal m_rotation;
205 qreal m_tangentialPressure;
206
207 // some funny debugging
208 dbgPlugins << "m_mouse.vel: " << m_mouse.vel;
209 dbgPlugins << "m_mouse.velx: " << m_mouse.velx;
210 dbgPlugins << "m_mouse.vely: " << m_mouse.vely;
211 dbgPlugins << "m_mouse.accx: " << m_mouse.accx;
212 dbgPlugins << "m_mouse.accy: " << m_mouse.accy;
213
214
215 dbgPlugins << "fixed: " << m_mouse.fixedangle;
216 dbgPlugins << "drag: " << m_curdrag;
217 dbgPlugins << "mass: " << m_curmass;
218 dbgPlugins << "xAngle: " << m_xangle;
219 dbgPlugins << "yAngle: " << m_yangle;
220
221#endif
222
223 m_odelx = delx;
224 m_odely = dely;
225
226 // how to change pressure in the KoPointerEvent???
227 return KoPointerEvent(event,now);
228}
229
230
232{
233 m_curdrag = drag;
234 m_configGroup.writeEntry("dragAmount", drag);
235}
236
237
239{
240 m_curmass = mass;
241 m_configGroup.writeEntry("massAmount", mass);
242}
243
244
246{
247 m_width = width;
248 m_configGroup.writeEntry("initWidth", width);
249}
250
251
252void KisToolDyna::slotSetWidthRange(double widthRange)
253{
254 m_widthRange = widthRange;
255 m_configGroup.writeEntry("initWidthRange", widthRange);
256}
257
258
260{
261 m_mouse.fixedangle = fixedAngle;
262 m_angleSelector->setEnabled(fixedAngle);
263 m_configGroup.writeEntry("useFixedAngle", fixedAngle);
264}
265
267{
268
269 QWidget * optionsWidget = KisToolFreehand::createOptionWidget();
270 optionsWidget->setObjectName(toolId() + " option widget");
271
272 m_optionLayout = new QGridLayout();
273
274 m_optionLayout->setContentsMargins(0, 0, 0, 0);
275 m_optionLayout->setSpacing(2);
277
278 QLabel* massLbl = new QLabel(i18n("Mass:"), optionsWidget);
279 m_massSPBox = new KisDoubleSliderSpinBox(optionsWidget);
280 m_massSPBox->setRange(0.0,1.0,2);
281 m_massSPBox->setSingleStep(0.01);
282 connect(m_massSPBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetMass(qreal)));
284
285 QLabel* dragLbl = new QLabel(i18n("Drag:"), optionsWidget);
286 m_dragSPBox = new KisDoubleSliderSpinBox(optionsWidget);
287 m_dragSPBox->setRange(0.0,1.0,2);
288 m_dragSPBox->setSingleStep(0.01);
289 connect(m_dragSPBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetDrag(qreal)));
291
292 //NOTE: so far unused, waiting for the changes to propagate rotation/pressure to freehand tool
293 // fixed angle might be for 2.4, but the later one for 2.5
294 m_chkFixedAngle = new QCheckBox(i18n("Fixed angle:"), optionsWidget);
295 m_chkFixedAngle->setEnabled(false);
296 connect(m_chkFixedAngle, SIGNAL(toggled(bool)), this, SLOT(slotSetFixedAngle(bool)));
297
298 m_angleSelector = new KisAngleSelector(optionsWidget);
302 m_angleSelector->setEnabled(false);
303 connect(m_angleSelector, SIGNAL(angleChanged(qreal)), this, SLOT(slotSetAngle(qreal)));
304
306
307 // read settings in from config
308 m_massSPBox->setValue(m_configGroup.readEntry("massAmount", 0.01));
309 m_dragSPBox->setValue(m_configGroup.readEntry("dragAmount", .98));
310 m_chkFixedAngle->setChecked((bool)m_configGroup.readEntry("useFixedAngle", false));
311 m_angleSelector->setAngle(m_configGroup.readEntry("angleAmount", 20));
312
313
314#if 0
315 QLabel* initWidthLbl = new QLabel(i18n("Initial width:"), optionWidget);
316 m_initWidthSPBox = new QDoubleSpinBox(optionWidget);
317 connect(m_initWidthSPBox, SIGNAL(valueChanged(double)), this, SLOT(slotSetDynaWidth(double)));
318 KisToolFreehand::addOptionWidgetOption(m_initWidthSPBox,initWidthLbl);
319
320 QLabel* widthRangeLbl = new QLabel(i18n("Width range:"), optionWidget);
321 m_widthRangeSPBox = new QDoubleSpinBox(optionWidget);
322 connect(m_widthRangeSPBox, SIGNAL(valueChanged(double)), this, SLOT(slotSetWidthRange(double)));
323 //KisToolFreehand::addOptionWidgetOption(m_widthRangeSPBox,widthRangeLbl);
324
325 m_initWidthSPBox->setValue(m_configGroup.readEntry("initWidth", 10));
326 m_widthRangeSPBox->setValue(m_configGroup.readEntry("initWidthRange", 20));
327
328
329#endif
330
331 return optionsWidget;
332}
333
335{
336 m_xangle = cos(angle * M_PI/180.0);
337 m_yangle = sin(angle * M_PI/180.0);
338
339 m_configGroup.writeEntry("angleAmount", angle);
340}
341
342
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void init(qreal x, qreal y)
@ IncreasingDirection_Clockwise
A widget with several options to select an angle.
@ FlipOptionsMode_MenuButton
The flip options are shown as a menu accessible via a options button.
void setFlipOptionsMode(FlipOptionsMode newMode)
Sets the mode in which the flip options should be shown.
void setIncreasingDirection(KisAngleGauge::IncreasingDirection newIncreasingDirection)
Sets the increasing direction in the angle gauge.
void setAngle(qreal newAngle)
Sets the current angle.
void setDecimals(int newNumberOfDecimals)
Sets the number of decimals (precision) used by the angle.
This class is a spinbox in which you can click and drag to set the value. A slider like bar is displa...
void setValue(qreal newValue)
void setRange(qreal newMinimum, qreal newMaximum, int newNumberOfDecimals=0, bool computeNewFastSliderStep=true)
Set the minimum and the maximum values of the range.
QPointF pixelToDocument(const QPointF &pixelCoord) const
void setMousePosition(const QPointF &point)
QCheckBox * m_chkFixedAngle
int applyFilter(qreal mx, qreal my)
void beginPrimaryAction(KoPointerEvent *event) override
void initStroke(KoPointerEvent *event) override
KisToolDyna(KoCanvasBase *canvas)
void continuePrimaryAction(KoPointerEvent *event) override
void slotSetFixedAngle(bool fixedAngle)
DynaFilter m_mouse
QPointF m_mousePos
qreal m_surfaceHeight
~KisToolDyna() override
QGridLayout * m_optionLayout
void activate(const QSet< KoShape * > &shapes) override
KoPointerEvent filterEvent(KoPointerEvent *event)
qreal m_surfaceWidth
KisDoubleSliderSpinBox * m_massSPBox
void slotSetMass(qreal mass)
KisAngleSelector * m_angleSelector
void slotSetDynaWidth(double width)
qreal flerp(qreal f0, qreal f1, qreal p)
void slotSetDrag(qreal drag)
void resetCursorStyle() override
QWidget * createOptionWidget() override
void slotSetAngle(qreal angle)
void slotSetWidthRange(double widthRange)
KConfigGroup m_configGroup
KisDoubleSliderSpinBox * m_dragSPBox
void continuePrimaryAction(KoPointerEvent *event) override
virtual void initStroke(KoPointerEvent *event)
void beginPrimaryAction(KoPointerEvent *event) override
void resetCursorStyle() override
void activate(const QSet< KoShape * > &shapes) override
void addOptionWidgetLayout(QLayout *layout)
Add the tool-specific layout to the default option widget layout.
virtual void addOptionWidgetOption(QWidget *control, QWidget *label=nullptr)
Add a widget and a label to the current option widget layout.
QPointF point
The point in document coordinates.
Q_INVOKABLE QString toolId() const
virtual QWidget * createOptionWidget()
void setIsOpacityPresetMode(bool value)
#define dbgPlugins
Definition kis_debug.h:51
#define M_PI
Definition kis_global.h:111
#define MIN_MASS
#define MAX_DRAG
#define MIN_VEL
#define MIN_ACC
#define MAX_MASS
#define MIN_DRAG
KUndo2MagicString kundo2_i18n(const char *text)
KisImageWSP currentImage()
Definition kis_tool.cc:393
QWidget * optionWidget
Definition kis_tool.cc:73
bool overrideCursorIfNotEditable()
Override the cursor appropriately if current node is not editable.
Definition kis_tool.cc:618