Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_current_outline_fetcher.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <KisOpacityOption.h>
10#include <KisRotationOption.h>
11#include <KisMirrorOption.h>
12#include <KisSharpnessOption.h>
13#include <KisMirrorProperties.h>
17#include <QElapsedTimer>
18#include "kis_algebra_2d.h"
20
21#define NOISY_UPDATE_SPEED 50 // Time in ms for outline updates to noisy brushes
22
24 Private(Options _optionsAvailable)
25 : optionsAvailable(_optionsAvailable)
26 , isDirty(true)
27 {
28 }
29
31
32 QScopedPointer<KisSizeOption> sizeOption;
33 QScopedPointer<KisRotationOption> rotationOption;
34 QScopedPointer<KisMirrorOption> mirrorOption;
35 QScopedPointer<KisSharpnessOption> sharpnessOption;
36
37 bool isDirty {false};
38 QElapsedTimer lastUpdateTime;
39
41 qreal lastSizeApplied {1.0};
43};
44
46 : d(new Private(optionsAvailable))
47{
48 d->lastUpdateTime.start();
49}
50
54
56{
57 d->isDirty = true;
58}
59
60KisOptimizedBrushOutline KisCurrentOutlineFetcher::fetchOutline(const KisPaintInformation &info, const KisPaintOpSettingsSP settings, const KisOptimizedBrushOutline &originalOutline, const KisPaintOpSettings::OutlineMode &mode, qreal alignForZoom, qreal additionalScale, qreal additionalRotation, bool tilt, qreal tiltcenterx, qreal tiltcentery) const
61{
62 if (d->isDirty) {
63 if (d->optionsAvailable & SIZE_OPTION) {
64 d->sizeOption.reset(new KisSizeOption(settings.data()));
65 }
66
67 if (d->optionsAvailable & ROTATION_OPTION) {
68 d->rotationOption.reset(new KisRotationOption(settings.data()));
69 }
70
71 if (d->optionsAvailable & MIRROR_OPTION) {
72 d->mirrorOption.reset(new KisMirrorOption(settings.data()));
73 }
74
75 if (d->optionsAvailable & SHARPNESS_OPTION) {
76 d->sharpnessOption.reset(new KisSharpnessOption(settings.data()));
77 }
78
79 d->isDirty = false;
80 }
81
82 qreal scale = additionalScale;
83 qreal rotation = additionalRotation;
84 bool needsUpdate = false;
85
86 // Randomized rotation at full speed looks noisy, so slow it down
87 if (d->lastUpdateTime.elapsed() > NOISY_UPDATE_SPEED) {
88 needsUpdate = true;
89 d->lastUpdateTime.restart();
90 }
91
92 if (d->sizeOption && !tilt && !mode.forceFullSize) {
93 if (!d->sizeOption->isRandom() || needsUpdate) {
94 d->lastSizeApplied = d->sizeOption->apply(info);
95 }
96 scale *= d->lastSizeApplied;
97 }
98
99 if (d->rotationOption && !tilt) {
100 if (!d->rotationOption->isRandom() || needsUpdate) {
101 d->lastRotationApplied = d->rotationOption->apply(info);
102 }
103 rotation += d->lastRotationApplied;
104 } else if (d->rotationOption && tilt) {
105 rotation += info.canvasRotation() * M_PI / 180.0;
106 }
107
108 qreal xFlip = 1.0;
109 qreal yFlip = 1.0;
110
111 if (d->mirrorOption) {
112 if (!d->mirrorOption->isRandom() || needsUpdate) {
113 d->lastMirrorApplied = d->mirrorOption->apply(info);
114 }
115
116 if (d->lastMirrorApplied.coordinateSystemFlipped) {
117 rotation = 2 * M_PI - rotation;
118 }
119
120 if (d->lastMirrorApplied.horizontalMirror) {
121 xFlip = -1.0;
122 }
123
124 if (d->lastMirrorApplied.verticalMirror) {
125 yFlip = -1.0;
126 }
127 }
128
129 QTransform rot;
130 rot.rotateRadians(-rotation);
131
132 QPointF hotSpot = originalOutline.boundingRect().center();
133 if (tilt) {
134 hotSpot.setX(tiltcenterx);
135 hotSpot.setY(tiltcentery);
136 }
137
138 QPointF pos = info.pos();
139 if (d->sharpnessOption && d->sharpnessOption->alignOutlineToPixels()) {
140 qint32 x = 0;
141 qint32 y = 0;
142 qreal subPixelX = 0.0;
143 qreal subPixelY = 0.0;
144 d->sharpnessOption->apply(info, pos - hotSpot, x, y, subPixelX, subPixelY);
145 pos = QPointF(x + subPixelX, y + subPixelY) + hotSpot;
146 }
147
148 // align cursor position to widget pixel grid to avoid noise
149 pos = KisAlgebra2D::alignForZoom(pos, alignForZoom);
150
151 QTransform T1 = QTransform::fromTranslate(-hotSpot.x(), -hotSpot.y());
152 QTransform T2 = QTransform::fromTranslate(pos.x(), pos.y());
153 QTransform S = QTransform::fromScale(xFlip * scale, yFlip * scale);
154
155 return originalOutline.mapped(T1 * rot * S * T2);
156}
Eigen::Matrix< double, 4, 2 > S
KisStandardOption< KisSizeOptionData > KisSizeOption
KisOptimizedBrushOutline fetchOutline(const KisPaintInformation &info, const KisPaintOpSettingsSP settings, const KisOptimizedBrushOutline &originalOutline, const KisPaintOpSettings::OutlineMode &mode, qreal alignForZoom, qreal additionalScale=1.0, qreal additionalRotation=0.0, bool tilt=false, qreal tiltcenterx=1.0, qreal tiltcentery=1.0) const
KisCurrentOutlineFetcher(Options optionsAvailable)
const QScopedPointer< Private > d
KisOptimizedBrushOutline mapped(const QTransform &t) const
const QPointF & pos() const
#define NOISY_UPDATE_SPEED
#define M_PI
Definition kis_global.h:111
QPointF alignForZoom(const QPointF &pt, qreal zoom)
QScopedPointer< KisRotationOption > rotationOption
QScopedPointer< KisMirrorOption > mirrorOption
QScopedPointer< KisSharpnessOption > sharpnessOption
QScopedPointer< KisSizeOption > sizeOption