1 /*
2 * Copyright (c) 2020 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "KisBezierTransformMesh.h"
20
21 #include "kis_grid_interpolation_tools.h"
22 #include "kis_debug.h"
23
hitTestPatch(const QPointF & pt,QPointF * localPointResult) const24 KisBezierTransformMesh::PatchIndex KisBezierTransformMesh::hitTestPatch(const QPointF &pt, QPointF *localPointResult) const {
25 auto result = endPatches();
26
27 const QRectF unitRect(0, 0, 1, 1);
28
29 for (auto it = beginPatches(); it != endPatches(); ++it) {
30 Patch patch = *it;
31
32 if (patch.dstBoundingRect().contains(pt)) {
33 const QPointF localPos = KisBezierUtils::calculateLocalPos(patch.points, pt);
34
35 if (unitRect.contains(localPos)) {
36
37 if (localPointResult) {
38 *localPointResult = localPos;
39 }
40
41 result = it;
42 break;
43 }
44 }
45 }
46
47 return result.patchIndex();
48 }
49
transformPatch(const KisBezierPatch & patch,const QPoint & srcQImageOffset,const QImage & srcImage,const QPoint & dstQImageOffset,QImage * dstImage)50 void KisBezierTransformMesh::transformPatch(const KisBezierPatch &patch, const QPoint &srcQImageOffset, const QImage &srcImage, const QPoint &dstQImageOffset, QImage *dstImage)
51 {
52 QVector<QPointF> originalPointsLocal;
53 QVector<QPointF> transformedPointsLocal;
54 QSize gridSize;
55
56 patch.sampleRegularGrid(gridSize, originalPointsLocal, transformedPointsLocal, QPointF(8,8));
57
58 const QRect dstBoundsI = patch.dstBoundingRect().toAlignedRect();
59 const QRect imageSize = QRect(dstQImageOffset, dstImage->size());
60 KIS_SAFE_ASSERT_RECOVER_NOOP(imageSize.contains(dstBoundsI));
61
62 {
63 GridIterationTools::QImagePolygonOp polygonOp(srcImage, *dstImage, srcQImageOffset, dstQImageOffset);
64
65 GridIterationTools::RegularGridIndexesOp indexesOp(gridSize);
66 GridIterationTools::iterateThroughGrid
67 <GridIterationTools::AlwaysCompletePolygonPolicy>(polygonOp, indexesOp,
68 gridSize,
69 originalPointsLocal,
70 transformedPointsLocal);
71 }
72 }
73
transformPatch(const KisBezierPatch & patch,KisPaintDeviceSP srcDevice,KisPaintDeviceSP dstDevice)74 void KisBezierTransformMesh::transformPatch(const KisBezierPatch &patch, KisPaintDeviceSP srcDevice, KisPaintDeviceSP dstDevice)
75 {
76 QVector<QPointF> originalPointsLocal;
77 QVector<QPointF> transformedPointsLocal;
78 QSize gridSize;
79
80 patch.sampleRegularGrid(gridSize, originalPointsLocal, transformedPointsLocal, QPointF(8,8));
81
82 {
83 GridIterationTools::PaintDevicePolygonOp polygonOp(srcDevice, dstDevice);
84
85 GridIterationTools::RegularGridIndexesOp indexesOp(gridSize);
86 GridIterationTools::iterateThroughGrid
87 <GridIterationTools::AlwaysCompletePolygonPolicy>(polygonOp, indexesOp,
88 gridSize,
89 originalPointsLocal,
90 transformedPointsLocal);
91 }
92 }
93
transformMesh(const QPoint & srcQImageOffset,const QImage & srcImage,const QPoint & dstQImageOffset,QImage * dstImage) const94 void KisBezierTransformMesh::transformMesh(const QPoint &srcQImageOffset, const QImage &srcImage, const QPoint &dstQImageOffset, QImage *dstImage) const
95 {
96 for (auto it = beginPatches(); it != endPatches(); ++it) {
97 transformPatch(*it, srcQImageOffset, srcImage, dstQImageOffset, dstImage);
98 }
99 }
100
transformMesh(KisPaintDeviceSP srcDevice,KisPaintDeviceSP dstDevice) const101 void KisBezierTransformMesh::transformMesh(KisPaintDeviceSP srcDevice, KisPaintDeviceSP dstDevice) const
102 {
103 for (auto it = beginPatches(); it != endPatches(); ++it) {
104 transformPatch(*it, srcDevice, dstDevice);
105 }
106 }
107
approxNeedRect(const QRect & rc) const108 QRect KisBezierTransformMesh::approxNeedRect(const QRect &rc) const
109 {
110 QRect result = rc;
111
112 for (auto it = beginPatches(); it != endPatches(); ++it) {
113 KisBezierPatch patch = *it;
114
115 if (patch.dstBoundingRect().intersects(rc)) {
116 result |= patch.srcBoundingRect().toAlignedRect();
117 }
118 }
119
120 return result;
121 }
122
approxChangeRect(const QRect & rc) const123 QRect KisBezierTransformMesh::approxChangeRect(const QRect &rc) const
124 {
125 QRect result = rc;
126
127 for (auto it = beginPatches(); it != endPatches(); ++it) {
128 const KisBezierPatch patch = *it;
129
130 if (patch.srcBoundingRect().intersects(rc)) {
131 result |= patch.dstBoundingRect().toAlignedRect();
132 }
133 }
134
135 return result;
136 }
137
138 #include <kis_dom_utils.h>
139
saveValue(QDomElement * parent,const QString & tag,const KisBezierTransformMesh & mesh)140 void KisBezierTransformMeshDetail::saveValue(QDomElement *parent, const QString &tag, const KisBezierTransformMesh &mesh)
141 {
142 QDomDocument doc = parent->ownerDocument();
143 QDomElement e = doc.createElement(tag);
144 parent->appendChild(e);
145
146 e.setAttribute("type", "transform-mesh");
147
148 KisDomUtils::saveValue(&e, "size", mesh.m_size);
149 KisDomUtils::saveValue(&e, "srcRect", mesh.m_originalRect);
150 KisDomUtils::saveValue(&e, "columns", mesh.m_columns);
151 KisDomUtils::saveValue(&e, "rows", mesh.m_rows);
152 KisDomUtils::saveValue(&e, "nodes", mesh.m_nodes);
153 }
154
loadValue(const QDomElement & e,KisBezierTransformMesh * mesh)155 bool KisBezierTransformMeshDetail::loadValue(const QDomElement &e, KisBezierTransformMesh *mesh)
156 {
157 if (!KisDomUtils::Private::checkType(e, "transform-mesh")) return false;
158
159 mesh->m_columns.clear();
160 mesh->m_rows.clear();
161 mesh->m_nodes.clear();
162
163 KisDomUtils::loadValue(e, "size", &mesh->m_size);
164 KisDomUtils::loadValue(e, "srcRect", &mesh->m_originalRect);
165 KisDomUtils::loadValue(e, "columns", &mesh->m_columns);
166 KisDomUtils::loadValue(e, "rows", &mesh->m_rows);
167 KisDomUtils::loadValue(e, "nodes", &mesh->m_nodes);
168
169 return true;
170 }
171