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 }