File indexing completed on 2024-05-19 04:25:07

0001 /*
0002  *  SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #ifndef KISBEZIERPATCHPARAMTOSOURCESAMPLER_H
0007 #define KISBEZIERPATCHPARAMTOSOURCESAMPLER_H
0008 
0009 #include "KisBezierPatch.h"
0010 #include "KisBezierUtils.h"
0011 #include "KisBezierPatchParamSpaceUtils.h"
0012 
0013 /**
0014  * A simple class that maps param-space point of a bezier patch into the source-range
0015  */
0016 struct KisBezierPatchParamToSourceSampler
0017 {
0018     using Range = KisBezierUtils::Range;
0019 
0020     KisBezierPatchParamToSourceSampler(const KisBezierPatch &_patch)
0021         : patch(_patch)
0022         , topLength(KisBezierUtils::curveLength(patch.points[KisBezierPatch::TL], patch.points[KisBezierPatch::TL_HC], patch.points[KisBezierPatch::TR_HC], patch.points[KisBezierPatch::TR], 0.01))
0023         , bottomLength(KisBezierUtils::curveLength(patch.points[KisBezierPatch::BL], patch.points[KisBezierPatch::BL_HC], patch.points[KisBezierPatch::BR_HC], patch.points[KisBezierPatch::BR], 0.01))
0024         , leftLength(KisBezierUtils::curveLength(patch.points[KisBezierPatch::TL], patch.points[KisBezierPatch::TL_VC], patch.points[KisBezierPatch::BL_VC], patch.points[KisBezierPatch::BL], 0.01))
0025         , rightLength(KisBezierUtils::curveLength(patch.points[KisBezierPatch::TR], patch.points[KisBezierPatch::TR_VC], patch.points[KisBezierPatch::BR_VC], patch.points[KisBezierPatch::BR], 0.01))
0026     {}
0027 
0028     KisBezierPatch patch;
0029 
0030     qreal topLength;
0031     qreal bottomLength;
0032 
0033     qreal leftLength;
0034     qreal rightLength ;
0035 
0036     Range xRange(qreal xParam) const
0037     {
0038         qreal xCoord1 = KisBezierUtils::curveLengthAtPoint(patch.points[KisBezierPatch::TL], patch.points[KisBezierPatch::TL_HC], patch.points[KisBezierPatch::TR_HC], patch.points[KisBezierPatch::TR], xParam, 0.01) / topLength;
0039         qreal xCoord2 = KisBezierUtils::curveLengthAtPoint(patch.points[KisBezierPatch::BL], patch.points[KisBezierPatch::BL_HC], patch.points[KisBezierPatch::BR_HC], patch.points[KisBezierPatch::BR], xParam, 0.01) / bottomLength;
0040 
0041         xCoord1 = patch.originalRect.left() + xCoord1 * patch.originalRect.width();
0042         xCoord2 = patch.originalRect.left() + xCoord2 * patch.originalRect.width();
0043 
0044         if (xCoord1 > xCoord2) {
0045             std::swap(xCoord1, xCoord2);
0046         }
0047 
0048         return {xCoord1, xCoord2};
0049     };
0050 
0051     Range yRange(qreal yParam) const
0052     {
0053         qreal yCoord1 = KisBezierUtils::curveLengthAtPoint(patch.points[KisBezierPatch::TL], patch.points[KisBezierPatch::TL_VC], patch.points[KisBezierPatch::BL_VC], patch.points[KisBezierPatch::BL], yParam, 0.01) / leftLength;
0054         qreal yCoord2 = KisBezierUtils::curveLengthAtPoint(patch.points[KisBezierPatch::TR], patch.points[KisBezierPatch::TR_VC], patch.points[KisBezierPatch::BR_VC], patch.points[KisBezierPatch::BR], yParam, 0.01) / rightLength;
0055 
0056         yCoord1 = patch.originalRect.top() + yCoord1 * patch.originalRect.height();
0057         yCoord2 = patch.originalRect.top() + yCoord2 * patch.originalRect.height();
0058 
0059         if (yCoord1 > yCoord2) {
0060             std::swap(yCoord1, yCoord2);
0061         }
0062 
0063         return {yCoord1, yCoord2};
0064     };
0065 
0066     QPointF point(qreal xParam, qreal yParam) const
0067     {
0068         using KisAlgebra2D::lerp;
0069 
0070         const Range xRange = this->xRange(xParam);
0071         const Range yRange = this->yRange(yParam);
0072 
0073         return QPointF(lerp(xRange.start, xRange.end, yParam),
0074                        lerp(yRange.start, yRange.end, xParam));
0075     }
0076 
0077     QPointF point(const QPointF &pt) const {
0078         return point(pt.x(), pt.y());
0079     }
0080 };
0081 
0082 #endif // KISBEZIERPATCHPARAMTOSOURCESAMPLER_H