Krita Source Code Documentation
Loading...
Searching...
No Matches
KisBezierPatch.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "KisBezierPatch.h"
8
9#include <QtMath>
10#include <kis_algebra_2d.h>
11#include "KisBezierUtils.h"
12
13#include "kis_debug.h"
14
16 QRectF result;
17
18 for (auto it = points.begin(); it != points.end(); ++it) {
20 }
21
22 return result;
23}
24
26 return originalRect;
27}
28
29QPointF KisBezierPatch::localToGlobal(const QPointF &pt) const
30{
32}
33
34QPointF KisBezierPatch::globalToLocal(const QPointF &pt) const
35{
37}
38
39void KisBezierPatch::sampleRegularGrid(QSize &gridSize, QVector<QPointF> &origPoints, QVector<QPointF> &transfPoints, const QPointF &dstStep) const
40{
43
44 const QRectF bounds = dstBoundingRect();
45 gridSize.rwidth() = qCeil(bounds.width() / dstStep.x());
46 gridSize.rheight() = qCeil(bounds.height() / dstStep.y());
47
48 const qreal topLength = KisBezierUtils::curveLength(points[TL], points[TL_HC], points[TR_HC], points[TR], 0.01);
49 const qreal bottomLength = KisBezierUtils::curveLength(points[BL], points[BL_HC], points[BR_HC], points[BR], 0.01);
50
51 const qreal leftLength = KisBezierUtils::curveLength(points[TL], points[TL_VC], points[BL_VC], points[BL], 0.01);
52 const qreal rightLength = KisBezierUtils::curveLength(points[TR], points[TR_VC], points[BR_VC], points[BR], 0.01);
53
54 struct Split {
55 QPointF p0;
56 QPointF relP1;
57 QPointF relP2;
58 QPointF p3;
59 qreal coord1;
60 qreal coord2;
61 qreal proportion;
62 };
63
64 std::vector<Split> verticalSplits;
65 std::vector<Split> horizontalSplits;
66
67 for (int y = 0; y < gridSize.height(); y++) {
68 const qreal yProportion = qreal(y) / (gridSize.height() - 1);
69
70 const qreal yCoord1 = KisBezierUtils::curveLengthAtPoint(points[TL], points[TL_VC], points[BL_VC], points[BL], yProportion, 0.01) / leftLength;
71 const qreal yCoord2 = KisBezierUtils::curveLengthAtPoint(points[TR], points[TR_VC], points[BR_VC], points[BR], yProportion, 0.01) / rightLength;
72
73 const QPointF p0 = bezierCurve(points[TL], points[TL_VC], points[BL_VC], points[BL], yProportion);
74
75 const QPointF relP1 = lerp(points[TL_HC] - points[TL], points[BL_HC] - points[BL], yProportion);
76 const QPointF relP2 = lerp(points[TR_HC] - points[TR], points[BR_HC] - points[BR], yProportion);
77
78 const QPointF p3 = bezierCurve(points[TR], points[TR_VC], points[BR_VC], points[BR], yProportion);
79
80 verticalSplits.push_back({p0, relP1, relP2, p3, yCoord1, yCoord2, yProportion});
81 }
82
83 for (int x = 0; x < gridSize.width(); x++) {
84 const qreal xProportion = qreal(x) / (gridSize.width() - 1);
85
86 const qreal xCoord1 = KisBezierUtils::curveLengthAtPoint(points[TL], points[TL_HC], points[TR_HC], points[TR], xProportion, 0.01) / topLength;
87 const qreal xCoord2 = KisBezierUtils::curveLengthAtPoint(points[BL], points[BL_HC], points[BR_HC], points[BR], xProportion, 0.01) / bottomLength;
88
89 const QPointF q0 = bezierCurve(points[TL], points[TL_HC], points[TR_HC], points[TR], xProportion);
90
91 const QPointF relQ1 = lerp(points[TL_VC] - points[TL], points[TR_VC] - points[TR], xProportion);
92 const QPointF relQ2 = lerp(points[BL_VC] - points[BL], points[BR_VC] - points[BR], xProportion);
93
94 const QPointF q3 = bezierCurve(points[BL], points[BL_HC], points[BR_HC], points[BR], xProportion);
95
96 horizontalSplits.push_back({q0, relQ1, relQ2, q3, xCoord1, xCoord2, xProportion});
97 }
98
99 for (int y = 0; y < gridSize.height(); y++) {
100 for (int x = 0; x < gridSize.width(); x++) {
101 const Split &ySplit = verticalSplits[y];
102 const Split &xSplit = horizontalSplits[x];
103
104 const QPointF transf1 = bezierCurve(ySplit.p0,
105 ySplit.p0 + ySplit.relP1,
106 ySplit.p3 + ySplit.relP2,
107 ySplit.p3,
108 xSplit.proportion);
109
110
111 const QPointF transf2 = bezierCurve(xSplit.p0,
112 xSplit.p0 + xSplit.relP1,
113 xSplit.p3 + xSplit.relP2,
114 xSplit.p3,
115 ySplit.proportion);
116
117
118 const QPointF transf = 0.5 * (transf1 + transf2);
119
120 const QPointF localPt(lerp(xSplit.coord1, xSplit.coord2, ySplit.proportion),
121 lerp(ySplit.coord1, ySplit.coord2, xSplit.proportion));
122 const QPointF orig = KisAlgebra2D::relativeToAbsolute(localPt, originalRect);
123
124 origPoints.append(orig);
125 transfPoints.append(transf);
126 }
127 }
128}
129
130void KisBezierPatch::sampleRegularGridSVG2(QSize &gridSize, QVector<QPointF> &origPoints, QVector<QPointF> &transfPoints, const QPointF &dstStep) const
131{
132 using KisAlgebra2D::lerp;
134
135 const QRectF bounds = dstBoundingRect();
136 gridSize.rwidth() = qCeil(bounds.width() / dstStep.x());
137 gridSize.rheight() = qCeil(bounds.height() / dstStep.y());
138
139 const qreal topLength = KisBezierUtils::curveLength(points[TL], points[TL_HC], points[TR_HC], points[TR], 0.01);
140 const qreal bottomLength = KisBezierUtils::curveLength(points[BL], points[BL_HC], points[BR_HC], points[BR], 0.01);
141
142 const qreal leftLength = KisBezierUtils::curveLength(points[TL], points[TL_VC], points[BL_VC], points[BL], 0.01);
143 const qreal rightLength = KisBezierUtils::curveLength(points[TR], points[TR_VC], points[BR_VC], points[BR], 0.01);
144
145
146 struct Split {
147 QPointF p0;
148 QPointF p3;
149 qreal coord1;
150 qreal coord2;
151 qreal proportion;
152 };
153
154 std::vector<Split> verticalSplits;
155 std::vector<Split> horizontalSplits;
156
157 for (int y = 0; y < gridSize.height(); y++) {
158 const qreal yProportion = qreal(y) / (gridSize.height() - 1);
159
160 const qreal yCoord1 = KisBezierUtils::curveLengthAtPoint(points[TL], points[TL_VC], points[BL_VC], points[BL], yProportion, 0.01) / leftLength;
161 const qreal yCoord2 = KisBezierUtils::curveLengthAtPoint(points[TR], points[TR_VC], points[BR_VC], points[BR], yProportion, 0.01) / rightLength;
162
163 const QPointF p0 = bezierCurve(points[TL], points[TL_VC], points[BL_VC], points[BL], yProportion);
164 const QPointF p3 = bezierCurve(points[TR], points[TR_VC], points[BR_VC], points[BR], yProportion);
165
166 verticalSplits.push_back({p0, p3, yCoord1, yCoord2, yProportion});
167 }
168
169 for (int x = 0; x < gridSize.width(); x++) {
170 const qreal xProportion = qreal(x) / (gridSize.width() - 1);
171
172 const qreal xCoord1 = KisBezierUtils::curveLengthAtPoint(points[TL], points[TL_HC], points[TR_HC], points[TR], xProportion, 0.01) / topLength;
173 const qreal xCoord2 = KisBezierUtils::curveLengthAtPoint(points[BL], points[BL_HC], points[BR_HC], points[BR], xProportion, 0.01) / bottomLength;
174
175 const QPointF q0 = bezierCurve(points[TL], points[TL_HC], points[TR_HC], points[TR], xProportion);
176 const QPointF q3 = bezierCurve(points[BL], points[BL_HC], points[BR_HC], points[BR], xProportion);
177
178 horizontalSplits.push_back({q0, q3, xCoord1, xCoord2, xProportion});
179 }
180
181 for (int y = 0; y < gridSize.height(); y++) {
182 for (int x = 0; x < gridSize.width(); x++) {
183 const Split &ySplit = verticalSplits[y];
184 const Split &xSplit = horizontalSplits[x];
185
186 const QPointF Sc = lerp(xSplit.p0, xSplit.p3, ySplit.proportion);
187 const QPointF Sd = lerp(ySplit.p0, ySplit.p3, xSplit.proportion);
188
189 const QPointF Sb =
190 lerp(lerp(points[TL], points[TR], xSplit.proportion),
191 lerp(points[BL], points[BR], xSplit.proportion),
192 ySplit.proportion);
193
194 const QPointF transf = Sc + Sd - Sb;
195
196 const QPointF localPt(lerp(xSplit.coord1, xSplit.coord2, ySplit.proportion),
197 lerp(ySplit.coord1, ySplit.coord2, xSplit.proportion));
198 const QPointF orig = KisAlgebra2D::relativeToAbsolute(localPt, originalRect);
199
200 origPoints.append(orig);
201 transfPoints.append(transf);
202 }
203 }
204}
205
206QDebug operator<<(QDebug dbg, const KisBezierPatch &p) {
207 dbg.nospace() << "Patch " << p.srcBoundingRect() << " -> " << p.dstBoundingRect() << "\n";
208 dbg.nospace() << " ( " << p.points[KisBezierPatch::TL] << " "<< p.points[KisBezierPatch::TR] << " " << p.points[KisBezierPatch::BL] << " " << p.points[KisBezierPatch::BR] << ") ";
209 return dbg.nospace();
210}
QDebug operator<<(QDebug dbg, const KisBezierPatch &p)
const Params2D p
QPointF q0
QPointF p0
QPointF q3
QPointF p3
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
void sampleRegularGrid(QSize &gridSize, QVector< QPointF > &origPoints, QVector< QPointF > &transfPoints, const QPointF &dstStep) const
QPointF localToGlobal(const QPointF &pt) const
QRectF dstBoundingRect() const
void sampleRegularGridSVG2(QSize &gridSize, QVector< QPointF > &origPoints, QVector< QPointF > &transfPoints, const QPointF &dstStep) const
std::array< QPointF, 12 > points
QPointF globalToLocal(const QPointF &pt) const
QRectF srcBoundingRect() const
#define bounds(x, a, b)
QPointF relativeToAbsolute(const QPointF &pt, const QRectF &rc)
Point lerp(const Point &pt1, const Point &pt2, qreal t)
void accumulateBounds(const Point &pt, Rect *bounds)
QPointF calculateLocalPos(const std::array< QPointF, 12 > &points, const QPointF &globalPoint)
calculates local (u,v) coordinates of the patch corresponding to globalPoint
qreal curveLengthAtPoint(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t, const qreal error)
QPointF calculateGlobalPos(const std::array< QPointF, 12 > &points, const QPointF &localPoint)
calculates global coordinate corresponding to the patch coordinate (u, v)
QPointF bezierCurve(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, qreal t)
qreal curveLength(const QPointF p0, const QPointF p1, const QPointF p2, const QPointF p3, const qreal error)