File indexing completed on 2024-05-12 15:58:50
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisBezierTransformMesh.h" 0008 0009 #include "kis_grid_interpolation_tools.h" 0010 #include "kis_debug.h" 0011 0012 KisBezierTransformMesh::PatchIndex KisBezierTransformMesh::hitTestPatch(const QPointF &pt, QPointF *localPointResult) const { 0013 auto result = endPatches(); 0014 0015 const QRectF unitRect(0, 0, 1, 1); 0016 0017 for (auto it = beginPatches(); it != endPatches(); ++it) { 0018 Patch patch = *it; 0019 0020 if (patch.dstBoundingRect().contains(pt)) { 0021 const QPointF localPos = KisBezierUtils::calculateLocalPos(patch.points, pt); 0022 0023 if (unitRect.contains(localPos)) { 0024 0025 if (localPointResult) { 0026 *localPointResult = localPos; 0027 } 0028 0029 result = it; 0030 break; 0031 } 0032 } 0033 } 0034 0035 return result.patchIndex(); 0036 } 0037 0038 void KisBezierTransformMesh::transformPatch(const KisBezierPatch &patch, const QPoint &srcQImageOffset, const QImage &srcImage, const QPoint &dstQImageOffset, QImage *dstImage) 0039 { 0040 QVector<QPointF> originalPointsLocal; 0041 QVector<QPointF> transformedPointsLocal; 0042 QSize gridSize; 0043 0044 patch.sampleRegularGrid(gridSize, originalPointsLocal, transformedPointsLocal, QPointF(8,8)); 0045 0046 const QRect dstBoundsI = patch.dstBoundingRect().toAlignedRect(); 0047 const QRect imageSize = QRect(dstQImageOffset, dstImage->size()); 0048 KIS_SAFE_ASSERT_RECOVER_NOOP(imageSize.contains(dstBoundsI)); 0049 0050 { 0051 GridIterationTools::QImagePolygonOp polygonOp(srcImage, *dstImage, srcQImageOffset, dstQImageOffset); 0052 0053 GridIterationTools::RegularGridIndexesOp indexesOp(gridSize); 0054 GridIterationTools::iterateThroughGrid 0055 <GridIterationTools::AlwaysCompletePolygonPolicy>(polygonOp, indexesOp, 0056 gridSize, 0057 originalPointsLocal, 0058 transformedPointsLocal); 0059 } 0060 } 0061 0062 void KisBezierTransformMesh::transformPatch(const KisBezierPatch &patch, KisPaintDeviceSP srcDevice, KisPaintDeviceSP dstDevice) 0063 { 0064 QVector<QPointF> originalPointsLocal; 0065 QVector<QPointF> transformedPointsLocal; 0066 QSize gridSize; 0067 0068 patch.sampleRegularGrid(gridSize, originalPointsLocal, transformedPointsLocal, QPointF(8,8)); 0069 0070 { 0071 GridIterationTools::PaintDevicePolygonOp polygonOp(srcDevice, dstDevice); 0072 0073 GridIterationTools::RegularGridIndexesOp indexesOp(gridSize); 0074 GridIterationTools::iterateThroughGrid 0075 <GridIterationTools::AlwaysCompletePolygonPolicy>(polygonOp, indexesOp, 0076 gridSize, 0077 originalPointsLocal, 0078 transformedPointsLocal); 0079 } 0080 } 0081 0082 void KisBezierTransformMesh::transformMesh(const QPoint &srcQImageOffset, const QImage &srcImage, const QPoint &dstQImageOffset, QImage *dstImage) const 0083 { 0084 for (auto it = beginPatches(); it != endPatches(); ++it) { 0085 transformPatch(*it, srcQImageOffset, srcImage, dstQImageOffset, dstImage); 0086 } 0087 } 0088 0089 void KisBezierTransformMesh::transformMesh(KisPaintDeviceSP srcDevice, KisPaintDeviceSP dstDevice) const 0090 { 0091 for (auto it = beginPatches(); it != endPatches(); ++it) { 0092 transformPatch(*it, srcDevice, dstDevice); 0093 } 0094 } 0095 0096 QRect KisBezierTransformMesh::approxNeedRect(const QRect &rc) const 0097 { 0098 QRect result = rc; 0099 0100 for (auto it = beginPatches(); it != endPatches(); ++it) { 0101 KisBezierPatch patch = *it; 0102 0103 if (patch.dstBoundingRect().intersects(rc)) { 0104 result |= patch.srcBoundingRect().toAlignedRect(); 0105 } 0106 } 0107 0108 return result; 0109 } 0110 0111 QRect KisBezierTransformMesh::approxChangeRect(const QRect &rc) const 0112 { 0113 QRect result = rc; 0114 0115 for (auto it = beginPatches(); it != endPatches(); ++it) { 0116 const KisBezierPatch patch = *it; 0117 0118 if (patch.srcBoundingRect().intersects(rc)) { 0119 result |= patch.dstBoundingRect().toAlignedRect(); 0120 } 0121 } 0122 0123 return result; 0124 } 0125 0126 #include <kis_dom_utils.h> 0127 0128 void KisBezierTransformMeshDetail::saveValue(QDomElement *parent, const QString &tag, const KisBezierTransformMesh &mesh) 0129 { 0130 QDomDocument doc = parent->ownerDocument(); 0131 QDomElement e = doc.createElement(tag); 0132 parent->appendChild(e); 0133 0134 e.setAttribute("type", "transform-mesh"); 0135 0136 KisDomUtils::saveValue(&e, "size", mesh.m_size); 0137 KisDomUtils::saveValue(&e, "srcRect", mesh.m_originalRect); 0138 KisDomUtils::saveValue(&e, "columns", mesh.m_columns); 0139 KisDomUtils::saveValue(&e, "rows", mesh.m_rows); 0140 KisDomUtils::saveValue(&e, "nodes", mesh.m_nodes); 0141 } 0142 0143 bool KisBezierTransformMeshDetail::loadValue(const QDomElement &e, KisBezierTransformMesh *mesh) 0144 { 0145 if (!KisDomUtils::Private::checkType(e, "transform-mesh")) return false; 0146 0147 mesh->m_columns.clear(); 0148 mesh->m_rows.clear(); 0149 mesh->m_nodes.clear(); 0150 0151 KisDomUtils::loadValue(e, "size", &mesh->m_size); 0152 KisDomUtils::loadValue(e, "srcRect", &mesh->m_originalRect); 0153 KisDomUtils::loadValue(e, "columns", &mesh->m_columns); 0154 KisDomUtils::loadValue(e, "rows", &mesh->m_rows); 0155 KisDomUtils::loadValue(e, "nodes", &mesh->m_nodes); 0156 0157 return true; 0158 }