Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_paintop_utils.h
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
7#ifndef __KIS_PAINTOP_UTILS_H
8#define __KIS_PAINTOP_UTILS_H
9
10#include "kis_global.h"
15
16#include "kritaimage_export.h"
17
18struct KisRenderedDab;
19
20namespace KisPaintOpUtils {
21
22template <class PaintOp>
23bool paintFan(PaintOp &op,
24 const KisPaintInformation &pi1,
25 const KisPaintInformation &pi2,
26 KisDistanceInformation *currentDistance,
27 qreal fanCornersStep)
28{
29 const qreal angleStep = fanCornersStep;
30 const qreal initialAngle = currentDistance->lastDrawingAngle();
31 const qreal finalAngle = pi2.drawingAngleSafe(*currentDistance);
32 const qreal fullDistance = shortestAngularDistance(initialAngle,
33 finalAngle);
34 qreal lastAngle = initialAngle;
35
36 int i = 0;
37
38 while (shortestAngularDistance(lastAngle, finalAngle) > angleStep) {
39 lastAngle = incrementInDirection(lastAngle, angleStep, finalAngle);
40
41 qreal t = angleStep * i++ / fullDistance;
42
43 QPointF pt = pi1.pos() + t * (pi2.pos() - pi1.pos());
45 pi.overrideDrawingAngle(lastAngle);
46 pi.paintAt(op, currentDistance);
47 }
48
49 return i;
50}
51
52
53template <class PaintOp>
54void paintLine(PaintOp &op,
55 const KisPaintInformation &pi1,
56 const KisPaintInformation &pi2,
57 KisDistanceInformation *currentDistance,
58 bool fanCornersEnabled,
59 qreal fanCornersStep)
60{
61 QPointF end = pi2.pos();
62 qreal endTime = pi2.currentTime();
63
64 KisPaintInformation pi = pi1;
65 qreal t = 0.0;
66
67 while ((t = currentDistance->getNextPointPosition(pi.pos(), end, pi.currentTime(), endTime)) >= 0.0) {
68 pi = KisPaintInformation::mix(t, pi, pi2);
69
70 if (fanCornersEnabled &&
71 currentDistance->hasLastPaintInformation()) {
72
73 paintFan(op,
74 currentDistance->lastPaintInformation(),
75 pi,
76 currentDistance,
77 fanCornersStep);
78 }
79
84 pi.paintAt(op, currentDistance);
85 }
86
87 /*
88 * Perform spacing and/or timing updates between dabs if appropriate. Typically, this will not
89 * happen if the above loop actually painted anything. This is because the
90 * getNextPointPosition() call before the paint operation will reset the accumulators in
91 * currentDistance and therefore make needsSpacingUpdate() and needsTimingUpdate() false. The
92 * temporal distance between pi1 and pi2 is typically too small for the accumulators to build
93 * back up enough to require a spacing or timing update after that. (The accumulated time values
94 * are updated not during the paint operation, but during the call to getNextPointPosition(),
95 * that is, updated during every paintLine() call.)
96 */
97 if (currentDistance->needsSpacingUpdate()) {
98 op.updateSpacing(pi2, *currentDistance);
99 }
100 if (currentDistance->needsTimingUpdate()) {
101 op.updateTiming(pi2, *currentDistance);
102 }
103}
104
113class KRITAIMAGE_EXPORT PositionHistory
114{
115public:
120 QPointF pushThroughHistory(const QPointF &pt, qreal zoom) {
121 QPointF result;
122 const qreal pointSwapThreshold = 7.0 / zoom;
123
128 const qreal distance = qMin(qAbs(pt.x() - m_second.x()), qAbs(pt.y() - m_second.y()));
129 const qreal coeff = qMin(1.0, distance / pointSwapThreshold);
130
131 if (coeff > 1.0 - std::numeric_limits<qreal>::epsilon()) {
132 result = m_second;
133 m_first = m_second;
134 m_second = pt;
135 } else {
140 result = m_first;
141 }
142
143 return result;
144 }
145
146 void reset(const QPointF &pt)
147 {
148 m_first = pt;
149 m_second = pt;
150 }
151
152private:
153 QPointF m_first;
154 QPointF m_second;
155};
156
157inline bool checkSizeTooSmall(qreal scale, qreal width, qreal height)
158{
159 return scale * width < 0.01 || scale * height < 0.01;
160}
161
162inline qreal calcAutoSpacing(qreal value, qreal coeff)
163{
164 return coeff * (value < 1.0 ? value : sqrt(value));
165}
166
167inline QPointF calcAutoSpacing(const QPointF &pt, qreal coeff, qreal lodScale)
168{
169 const qreal invLodScale = 1.0 / lodScale;
170 const QPointF lod0Point = invLodScale * pt;
171
172 return lodScale * QPointF(calcAutoSpacing(lod0Point.x(), coeff), calcAutoSpacing(lod0Point.y(), coeff));
173}
174
175KRITAIMAGE_EXPORT
177 qreal dabHeight,
178 qreal extraScale,
179 bool distanceSpacingEnabled,
180 bool isotropicSpacing,
181 qreal rotation,
182 bool axesFlipped,
183 qreal spacingVal,
184 bool autoSpacingActive,
185 qreal autoSpacingCoeff,
186 qreal lodScale);
187
188KRITAIMAGE_EXPORT
189KisTimingInformation effectiveTiming(bool timingEnabled,
190 qreal timingInterval,
191 qreal rateExtraScale);
192
193KRITAIMAGE_EXPORT
194QVector<QRect> splitAndFilterDabRect(const QRect &totalRect, const QVector<QRect> &dabRects, int idealPatchSize);
195
196KRITAIMAGE_EXPORT
197QVector<QRect> splitDabsIntoRects(const QVector<QRect> &dabRects, int idealNumRects, int diameter, qreal spacing);
198
199}
200
201#endif /* __KIS_PAINTOP_UTILS_H */
float value(const T *src, size_t ch)
qreal distance(const QPointF &p1, const QPointF &p2)
void paintAt(PaintOp &op, KisDistanceInformation *distanceInfo)
const QPointF & pos() const
qreal drawingAngleSafe(const KisDistanceInformation &distance) const
XXX !!! :-| Please add dox!
static KisPaintInformation mix(const QPointF &p, qreal t, const KisPaintInformation &p1, const KisPaintInformation &p2)
qreal currentTime() const
Number of ms since the beginning of the stroke.
QPointF pushThroughHistory(const QPointF &pt, qreal zoom)
qreal incrementInDirection(qreal a, qreal inc, qreal direction)
Definition kis_global.h:147
qreal shortestAngularDistance(qreal a, qreal b)
Definition kis_global.h:140
qreal calcAutoSpacing(qreal value, qreal coeff)
KisSpacingInformation effectiveSpacing(qreal dabWidth, qreal dabHeight, qreal extraScale, bool distanceSpacingEnabled, bool isotropicSpacing, qreal rotation, bool axesFlipped, qreal spacingVal, bool autoSpacingActive, qreal autoSpacingCoeff, qreal lodScale)
bool paintFan(PaintOp &op, const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance, qreal fanCornersStep)
bool checkSizeTooSmall(qreal scale, qreal width, qreal height)
void paintLine(PaintOp &op, const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance, bool fanCornersEnabled, qreal fanCornersStep)
KisTimingInformation effectiveTiming(bool timingEnabled, qreal timingInterval, qreal rateExtraScale)
QVector< QRect > splitAndFilterDabRect(const QRect &totalRect, const QVector< QRect > &dabRects, int idealPatchSize)
QVector< QRect > splitDabsIntoRects(const QVector< QRect > &dabRects, int idealNumRects, int diameter, qreal spacing)
KisPaintInformation lastPaintInformation
qreal getNextPointPosition(const QPointF &start, const QPointF &end, qreal startTime, qreal endTime)