Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_paintop.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
3 * SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
4 * SPDX-FileCopyrightText: 2004 Clarence Dang <dang@kde.org>
5 * SPDX-FileCopyrightText: 2004 Adrian Page <adrian@pagenet.plus.com>
6 * SPDX-FileCopyrightText: 2004, 2007, 2010 Cyrille Berger <cberger@cberger.net>
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "kis_paintop.h"
12
13#include <QtMath>
14
15#include <KoColor.h>
16#include <KoColorSpace.h>
17#include <KoPointerEvent.h>
18
19#include "kis_painter.h"
20#include "kis_layer.h"
21
22#include "kis_image.h"
23#include "kis_paint_device.h"
24#include "kis_global.h"
25#include "kis_datamanager.h"
28#include "kis_vec.h"
31#include "kis_paintop_utils.h"
32
33
34#define BEZIER_FLATNESS_THRESHOLD 0.5
36
37#include <qnumeric.h>
38
39struct Q_DECL_HIDDEN KisPaintOp::Private {
41 : q(_q) {}
42
43 KisPaintOp *q {nullptr};
44
46 KisPainter* painter {nullptr};
47
48 bool fanCornersEnabled {false};
49 qreal fanCornersStep {1.0};
50};
51
52
53KisPaintOp::KisPaintOp(KisPainter * painter) : d(new Private(this))
54{
55 d->painter = painter;
56}
57
59{
60 d->dab.clear();
61 delete d;
62}
63
65{
66 return cachedDab(d->painter->device()->colorSpace());
67}
68
70{
71 if (!d->dab || *d->dab->colorSpace() != *cs) {
72 d->dab = new KisFixedPaintDevice(cs);
73 }
74 return d->dab;
75}
76
77void KisPaintOp::setFanCornersInfo(bool fanCornersEnabled, qreal fanCornersStep)
78{
79 d->fanCornersEnabled = fanCornersEnabled;
80 d->fanCornersStep = fanCornersStep;
81}
82
83void KisPaintOp::splitCoordinate(qreal coordinate, qint32 *whole, qreal *fraction)
84{
85 const qint32 i = qFloor(coordinate);
86 const qreal f = coordinate - i;
87
88 *whole = i;
89 *fraction = f;
90}
91
93{
94 Q_UNUSED(jobs);
95 return std::make_pair(40, false);
96}
97
98static void paintBezierCurve(KisPaintOp *paintOp,
99 const KisPaintInformation &pi1,
100 const KisVector2D &control1,
101 const KisVector2D &control2,
102 const KisPaintInformation &pi2,
103 KisDistanceInformation *currentDistance
104 )
105{
106 LineEquation line = LineEquation::Through(toKisVector2D(pi1.pos()), toKisVector2D(pi2.pos()));
107 qreal d1 = line.absDistance(control1);
108 qreal d2 = line.absDistance(control2);
109
111 || qIsNaN(d1) || qIsNaN(d2)) {
112 paintOp->paintLine(pi1, pi2, currentDistance);
113 } else {
114 // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
115 KisVector2D l2 = (toKisVector2D(pi1.pos()) + control1) / 2;
116 KisVector2D h = (control1 + control2) / 2;
117 KisVector2D l3 = (l2 + h) / 2;
118 KisVector2D r3 = (control2 + toKisVector2D(pi2.pos())) / 2;
119 KisVector2D r2 = (h + r3) / 2;
120 KisVector2D l4 = (l3 + r2) / 2;
121
122 KisPaintInformation middlePI = KisPaintInformation::mix(toQPointF(l4), 0.5, pi1, pi2);
123
124 paintBezierCurve(paintOp, pi1, l2, l3, middlePI, currentDistance);
125 paintBezierCurve(paintOp, middlePI, r2, r3, pi2, currentDistance);
126 }
127}
128
130 const QPointF &control1,
131 const QPointF &control2,
132 const KisPaintInformation &pi2,
133 KisDistanceInformation *currentDistance)
134{
135 return ::paintBezierCurve(this, pi1, toKisVector2D(control1), toKisVector2D(control2), pi2, currentDistance);
136}
137
138
140 const KisPaintInformation &pi2,
141 KisDistanceInformation *currentDistance)
142{
143 KisPaintOpUtils::paintLine(*this, pi1, pi2, currentDistance,
144 d->fanCornersEnabled,
145 d->fanCornersStep);
146}
147
149{
150 Q_ASSERT(currentDistance);
151 KisPaintInformation pi(info);
152 pi.paintAt(*this, currentDistance);
153}
154
156 KisDistanceInformation &currentDistance) const
157{
158 KisPaintInformation pi(info);
159 KisSpacingInformation spacingInfo;
160 {
162 = pi.registerDistanceInformation(&currentDistance);
163 spacingInfo = updateSpacingImpl(pi);
164 }
165
166 currentDistance.updateSpacing(spacingInfo);
167}
168
170 KisDistanceInformation &currentDistance) const
171{
172 KisPaintInformation pi(info);
173 KisTimingInformation timingInfo;
174 {
176 = pi.registerDistanceInformation(&currentDistance);
177 timingInfo = updateTimingImpl(pi);
178 }
179
180 currentDistance.updateTiming(timingInfo);
181}
182
184{
185 Q_UNUSED(info);
186 return KisTimingInformation();
187}
188
190{
191 return d->painter;
192}
193
195{
196 return d->painter->device();
197}
QPointF r2
QPointF r3
void paintAt(PaintOp &op, KisDistanceInformation *distanceInfo)
const QPointF & pos() const
DistanceInformationRegistrar registerDistanceInformation(KisDistanceInformation *distance)
static KisPaintInformation mix(const QPointF &p, qreal t, const KisPaintInformation &p1, const KisPaintInformation &p2)
static void paintBezierCurve(KisPaintOp *paintOp, const KisPaintInformation &pi1, const KisVector2D &control1, const KisVector2D &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
#define BEZIER_FLATNESS_THRESHOLD
Eigen::Hyperplane< qreal, 2 > LineEquation
KisVector2D toKisVector2D(const QPointF &p)
Definition kis_vec.h:19
Eigen::Matrix< qreal, 2, 1 > KisVector2D
Definition kis_vec.h:17
QPointF toQPointF(const ExpressionType &expr)
Definition kis_vec.h:29
void paintLine(PaintOp &op, const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance, bool fanCornersEnabled, qreal fanCornersStep)
void updateTiming(const KisTimingInformation &timing)
void updateSpacing(const KisSpacingInformation &spacing)
KisPainter * painter
void updateTiming(const KisPaintInformation &info, KisDistanceInformation &currentDistance) const
virtual KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const =0
void paintAt(const KisPaintInformation &info, KisDistanceInformation *currentDistance)
KisFixedPaintDeviceSP dab
virtual ~KisPaintOp()
qreal fanCornersStep
KisPaintOp(KisPainter *painter)
KisPaintDeviceSP source() const
virtual KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const
KisFixedPaintDeviceSP cachedDab()
bool fanCornersEnabled
virtual std::pair< int, bool > doAsynchronousUpdate(QVector< KisRunnableStrokeJobData * > &jobs)
void updateSpacing(const KisPaintInformation &info, KisDistanceInformation &currentDistance) const
static void splitCoordinate(qreal coordinate, qint32 *whole, qreal *fraction)
virtual void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
Private(KisPaintOp *_q)
virtual void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
Private *const d
void setFanCornersInfo(bool fanCornersEnabled, qreal fanCornersStep)