File indexing completed on 2024-05-12 15:57:00

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISBEZIERMESH_H
0008 #define KISBEZIERMESH_H
0009 
0010 #include <kritaglobal_export.h>
0011 
0012 #include <QDebug>
0013 
0014 #include <KisBezierUtils.h>
0015 #include <KisBezierPatch.h>
0016 
0017 #include <boost/iterator/iterator_facade.hpp>
0018 #include <boost/operators.hpp>
0019 
0020 #include <functional>
0021 #include "KisCppQuirks.h"
0022 
0023 #include "kis_debug.h"
0024 
0025 class QDomElement;
0026 
0027 namespace KisBezierMeshDetails {
0028 
0029 struct BaseMeshNode : public boost::equality_comparable<BaseMeshNode> {
0030     BaseMeshNode() = default;
0031 
0032     BaseMeshNode(const QPointF &_node)
0033         : leftControl(_node),
0034           topControl(_node),
0035           node(_node),
0036           rightControl(_node),
0037           bottomControl(_node)
0038     {
0039     }
0040 
0041     bool operator==(const BaseMeshNode &rhs) const {
0042         return leftControl == rhs.leftControl &&
0043                 topControl == rhs.topControl &&
0044                 node == rhs.node &&
0045                 rightControl == rhs.rightControl &&
0046                 bottomControl == rhs.bottomControl;
0047     }
0048 
0049     void setLeftControlRelative(const QPointF &value) {
0050         leftControl = value + node;
0051     }
0052 
0053     QPointF leftControlRelative() const {
0054         return leftControl - node;
0055     }
0056 
0057     void setRightControlRelative(const QPointF &value) {
0058         rightControl = value + node;
0059     }
0060 
0061     QPointF rightControlRelative() const {
0062         return rightControl - node;
0063     }
0064 
0065     void setTopControlRelative(const QPointF &value) {
0066         topControl = value + node;
0067     }
0068 
0069     QPointF topControlRelative() const {
0070         return topControl - node;
0071     }
0072 
0073     void setBottomControlRelative(const QPointF &value) {
0074         bottomControl = value + node;
0075     }
0076 
0077     QPointF bottomControlRelative() const {
0078         return bottomControl - node;
0079     }
0080 
0081     void translate(const QPointF &offset) {
0082         leftControl += offset;
0083         topControl += offset;
0084         node += offset;
0085         rightControl += offset;
0086         bottomControl += offset;
0087     }
0088 
0089     void transform(const QTransform &t) {
0090         leftControl = t.map(leftControl);
0091         topControl = t.map(topControl);
0092         node = t.map(node);
0093         rightControl = t.map(rightControl);
0094         bottomControl = t.map(bottomControl);
0095     }
0096 
0097     QPointF leftControl;
0098     QPointF topControl;
0099     QPointF node;
0100     QPointF rightControl;
0101     QPointF bottomControl;
0102 };
0103 
0104 inline void lerpNodeData(const BaseMeshNode &left, const BaseMeshNode &right, qreal t, BaseMeshNode &dst)
0105 {
0106     Q_UNUSED(left);
0107     Q_UNUSED(right);
0108     Q_UNUSED(t);
0109     Q_UNUSED(dst);
0110 }
0111 
0112 inline void assignPatchData(KisBezierPatch *patch,
0113                             const QRectF &srcRect,
0114                             const BaseMeshNode &tl,
0115                             const BaseMeshNode &tr,
0116                             const BaseMeshNode &bl,
0117                             const BaseMeshNode &br)
0118 {
0119     patch->originalRect = srcRect;
0120     Q_UNUSED(tl);
0121     Q_UNUSED(tr);
0122     Q_UNUSED(bl);
0123     Q_UNUSED(br);
0124 }
0125 
0126 template<typename NodeArg = BaseMeshNode,
0127          typename PatchArg = KisBezierPatch>
0128 class Mesh : public boost::equality_comparable<Mesh<NodeArg, PatchArg>>
0129 {
0130 public:
0131     using Node = NodeArg;
0132     using Patch = PatchArg;
0133 
0134     struct PatchIndex : public QPoint, boost::additive<PatchIndex, QPoint>
0135     {
0136         using QPoint::QPoint;
0137         PatchIndex& operator+=(const QPoint &rhs) {
0138             QPoint::operator+=(rhs);
0139             return *this;
0140         }
0141         PatchIndex& operator-=(const QPoint &rhs) {
0142             QPoint::operator-=(rhs);
0143             return *this;
0144         }
0145     };
0146 
0147     struct NodeIndex : public QPoint, boost::additive<NodeIndex, QPoint>
0148     {
0149         using QPoint::QPoint;
0150         NodeIndex& operator+=(const QPoint &rhs) {
0151             QPoint::operator+=(rhs);
0152             return *this;
0153         }
0154         NodeIndex& operator-=(const QPoint &rhs) {
0155             QPoint::operator-=(rhs);
0156             return *this;
0157         }
0158     };
0159 
0160     using SegmentIndex = std::pair<NodeIndex, int>;
0161 
0162     struct ControlPointIndex : public boost::equality_comparable<ControlPointIndex>
0163     {
0164         enum ControlType {
0165             LeftControl = 0,
0166             TopControl,
0167             RightControl,
0168             BottomControl,
0169             Node
0170         };
0171 
0172         ControlPointIndex()  = default;
0173 
0174         ControlPointIndex(NodeIndex _nodeIndex, ControlType _controlType)
0175             : nodeIndex(_nodeIndex),
0176               controlType(_controlType)
0177         {
0178         }
0179 
0180         NodeIndex nodeIndex;
0181         ControlType controlType;
0182 
0183         inline bool isNode() const {
0184             return controlType == Node;
0185         }
0186 
0187         inline bool isControlPoint() const {
0188             return controlType != Node;
0189         }
0190 
0191         template <class NodeType,
0192                   class PointType = std::add_const_if_t<std::is_const<NodeType>::value, QPointF>>
0193         static
0194         PointType& controlPoint(NodeType &node, ControlType controlType) {
0195             return
0196                 controlType == LeftControl ? node.leftControl :
0197                 controlType == RightControl ? node.rightControl :
0198                 controlType == TopControl ? node.topControl :
0199                 controlType == BottomControl ? node.bottomControl :
0200                 node.node;
0201         }
0202 
0203         QPointF& controlPoint(Mesh::Node &node) {
0204             return controlPoint(node, controlType);
0205         }
0206 
0207         friend bool operator==(const ControlPointIndex &lhs, const ControlPointIndex &rhs) {
0208             return lhs.nodeIndex == rhs.nodeIndex && lhs.controlType == rhs.controlType;
0209         }
0210 
0211         friend QDebug operator<<(QDebug dbg, const Mesh::ControlPointIndex &index) {
0212             dbg.nospace() << "ControlPointIndex ("
0213                           << index.nodeIndex.x() << ", " << index.nodeIndex.x() << ", ";
0214 
0215             switch (index.controlType) {
0216             case Mesh::ControlType::Node:
0217                 dbg.nospace() << "Node";
0218                 break;
0219             case Mesh::ControlType::LeftControl:
0220                 dbg.nospace() << "LeftControl";
0221                 break;
0222             case Mesh::ControlType::RightControl:
0223                 dbg.nospace() << "RightControl";
0224                 break;
0225             case Mesh::ControlType::TopControl:
0226                 dbg.nospace() << "TopControl";
0227                 break;
0228             case Mesh::ControlType::BottomControl:
0229                 dbg.nospace() << "BottomControl";
0230                 break;
0231             }
0232 
0233             dbg.nospace() << ")";
0234             return dbg.space();
0235         }
0236     };
0237 
0238     using ControlType = typename ControlPointIndex::ControlType;
0239 
0240 private:
0241     template<bool is_const>
0242     class segment_iterator_impl;
0243 
0244     template<bool is_const>
0245     class control_point_iterator_impl;
0246 
0247     template<bool is_const>
0248     class patch_iterator_impl :
0249         public boost::iterator_facade <patch_iterator_impl<is_const>,
0250                                        Patch,
0251                                        boost::random_access_traversal_tag,
0252                                        Patch>
0253     {
0254         using PointType = std::add_const_if_t<is_const, QPointF>;
0255         using MeshType = std::add_const_if_t<is_const, Mesh>;
0256         using SegmentIteratorType = segment_iterator_impl<is_const>;
0257         using ControlPointIteratorType = control_point_iterator_impl<is_const>;
0258 
0259     public:
0260         patch_iterator_impl()
0261             : m_mesh(0),
0262               m_col(0),
0263               m_row(0) {}
0264 
0265         patch_iterator_impl(MeshType* mesh, int col, int row)
0266             : m_mesh(mesh),
0267               m_col(col),
0268               m_row(row)
0269         {
0270         }
0271 
0272         Mesh::PatchIndex patchIndex() const {
0273             return {m_col, m_row};
0274         }
0275 
0276         SegmentIteratorType segmentP() const;
0277         SegmentIteratorType segmentQ() const;
0278         SegmentIteratorType segmentR() const;
0279         SegmentIteratorType segmentS() const;
0280 
0281         ControlPointIteratorType nodeTopLeft() const;
0282         ControlPointIteratorType nodeTopRight() const;
0283         ControlPointIteratorType nodeBottomLeft() const;
0284         ControlPointIteratorType nodeBottomRight() const;
0285 
0286         bool isValid() const {
0287             return
0288                 m_col >= 0 &&
0289                 m_col < m_mesh->size().width() - 1 &&
0290                 m_row >= 0 &&
0291                 m_row < m_mesh->size().height() - 1;
0292         }
0293 
0294     private:
0295         friend class boost::iterator_core_access;
0296 
0297         void increment() {
0298             m_col++;
0299             if (m_col >= m_mesh->m_size.width() - 1) {
0300                 m_col = 0;
0301                 m_row++;
0302             }
0303         }
0304 
0305         void decrement() {
0306             m_col--;
0307             if (m_col < 0) {
0308                 m_col = m_mesh->m_size.width() - 2;
0309                 m_row--;
0310             }
0311         }
0312 
0313         void advance(int n) {
0314             const int index = m_row * (m_mesh->m_size.width() - 1) + m_col + n;
0315 
0316             m_row = index / (m_mesh->m_size.width() - 1);
0317             m_col = index % (m_mesh->m_size.width() - 1);
0318 
0319             KIS_SAFE_ASSERT_RECOVER_NOOP(m_row < m_mesh->m_size.height() - 1);
0320         }
0321 
0322         int distance_to(const patch_iterator_impl &z) const {
0323             const int index = m_row * (m_mesh->m_size.width() - 1) + m_col;
0324             const int otherIndex = z.m_row * (m_mesh->m_size.width() - 1) + z.m_col;
0325 
0326             return otherIndex - index;
0327         }
0328 
0329         bool equal(patch_iterator_impl const& other) const {
0330             return m_row == other.m_row &&
0331                     m_col == other.m_col &&
0332                 m_mesh == other.m_mesh;
0333         }
0334 
0335         Patch dereference() const {
0336             return m_mesh->makePatch(m_col, m_row);
0337         }
0338 
0339     private:
0340 
0341         MeshType *m_mesh;
0342         int m_col;
0343         int m_row;
0344     };
0345 
0346     template<bool is_const>
0347     class control_point_iterator_impl :
0348         public boost::iterator_facade <control_point_iterator_impl<is_const>,
0349                                        std::add_const_if_t<is_const, QPointF>,
0350                                        boost::bidirectional_traversal_tag>
0351     {
0352         using PointType = std::add_const_if_t<is_const, QPointF>;
0353         using NodeType = std::add_const_if_t<is_const, Node>;
0354         using MeshType = std::add_const_if_t<is_const, Mesh>;
0355         using SegmentIteratorType = segment_iterator_impl<is_const>;
0356 
0357     public:
0358         control_point_iterator_impl()
0359             : m_mesh(0),
0360               m_col(0),
0361               m_row(0),
0362               m_controlIndex(0)
0363         {}
0364 
0365         control_point_iterator_impl(MeshType* mesh, int col, int row, int controlIndex)
0366             : m_mesh(mesh),
0367               m_col(col),
0368               m_row(row),
0369               m_controlIndex(controlIndex)
0370         {
0371         }
0372 
0373         Mesh::ControlType type() const {
0374             return Mesh::ControlType(m_controlIndex);
0375         }
0376 
0377         int col() const {
0378             return m_col;
0379         }
0380 
0381         int row() const {
0382             return m_row;
0383         }
0384 
0385         Mesh::ControlPointIndex controlIndex() const {
0386             return Mesh::ControlPointIndex(nodeIndex(), type());
0387         }
0388 
0389         Mesh::NodeIndex nodeIndex() const {
0390             return Mesh::NodeIndex(m_col, m_row);
0391         }
0392 
0393         NodeType& node() const {
0394             return m_mesh->node(m_col, m_row);
0395         }
0396 
0397         bool isLeftBorder() const {
0398             return m_col == 0;
0399         }
0400 
0401         bool isRightBorder() const {
0402             return m_col == m_mesh->size().width() - 1;
0403         }
0404 
0405         bool isTopBorder() const {
0406             return m_row == 0;
0407         }
0408 
0409         bool isBottomBorder() const {
0410             return m_row == m_mesh->size().height() - 1;
0411         }
0412 
0413 
0414         bool isBorderNode() const {
0415             return isLeftBorder() || isRightBorder() || isTopBorder() || isBottomBorder();
0416         }
0417 
0418         bool isCornerNode() const {
0419             return (isLeftBorder() + isRightBorder() + isTopBorder() + isBottomBorder()) > 1;
0420         }
0421 
0422         bool isNode() const {
0423             return type() == Mesh::ControlPointIndex::Node;
0424         }
0425 
0426         control_point_iterator_impl symmetricControl() const {
0427             typename Mesh::ControlPointIndex::ControlType newIndex =
0428                     Mesh::ControlPointIndex::Node;
0429 
0430             switch (type()) {
0431             case Mesh::ControlPointIndex::Node:
0432                 newIndex = Mesh::ControlPointIndex::Node;
0433                 break;
0434             case Mesh::ControlPointIndex::LeftControl:
0435                 newIndex = Mesh::ControlPointIndex::RightControl;
0436                 break;
0437             case Mesh::ControlPointIndex::RightControl:
0438                 newIndex = Mesh::ControlPointIndex::LeftControl;
0439                 break;
0440             case Mesh::ControlPointIndex::TopControl:
0441                 newIndex = Mesh::ControlPointIndex::BottomControl;
0442                 break;
0443             case Mesh::ControlPointIndex::BottomControl:
0444                 newIndex = Mesh::ControlPointIndex::TopControl;
0445                 break;
0446             }
0447 
0448             control_point_iterator_impl it(m_mesh, m_col, m_row, newIndex);
0449 
0450             if (!it.controlIsValid()) {
0451                 it = m_mesh->endControlPoints();
0452             }
0453 
0454             return it;
0455         }
0456 
0457         SegmentIteratorType topSegment() const;
0458         SegmentIteratorType bottomSegment() const;
0459         SegmentIteratorType leftSegment() const;
0460         SegmentIteratorType rightSegment() const;
0461 
0462         bool isValid() const {
0463             return nodeIsValid() && controlIsValid();
0464         }
0465 
0466     private:
0467         friend class boost::iterator_core_access;
0468 
0469         bool nodeIsValid() const {
0470             return m_col >= 0 && m_row >= 0 && m_col < m_mesh->size().width() && m_row < m_mesh->size().height();
0471         }
0472 
0473         bool controlIsValid() const {
0474             if (m_col == 0 && m_controlIndex == Mesh::ControlType::LeftControl) {
0475                 return false;
0476             }
0477 
0478             if (m_col == m_mesh->m_size.width() - 1 && m_controlIndex == Mesh::ControlType::RightControl) {
0479                 return false;
0480             }
0481 
0482             if (m_row == 0 && m_controlIndex == Mesh::ControlType::TopControl) {
0483                 return false;
0484             }
0485 
0486             if (m_row == m_mesh->m_size.height() - 1 && m_controlIndex == Mesh::ControlType::BottomControl) {
0487                 return false;
0488             }
0489 
0490             return true;
0491         }
0492 
0493         void increment() {
0494             do {
0495                 m_controlIndex++;
0496                 if (m_controlIndex > 4) {
0497                     m_controlIndex = 0;
0498                     m_col++;
0499                     if (m_col >= m_mesh->m_size.width()) {
0500                         m_col = 0;
0501                         m_row++;
0502                     }
0503                 }
0504             } while (nodeIsValid() && !controlIsValid());
0505         }
0506 
0507         void decrement() {
0508             do {
0509                 m_controlIndex--;
0510                 if (m_controlIndex < 0) {
0511                     m_controlIndex = 4;
0512                     m_col--;
0513                     if (m_col < 0) {
0514                         m_col = m_mesh->m_size.width() - 1;
0515                         m_row--;
0516                     }
0517                 }
0518             } while (nodeIsValid() && !controlIsValid());
0519         }
0520 
0521 
0522         bool equal(control_point_iterator_impl const& other) const {
0523             return m_controlIndex == other.m_controlIndex &&
0524                 m_row == other.m_row &&
0525                 m_col == other.m_col &&
0526                 m_mesh == other.m_mesh;
0527         }
0528 
0529         PointType& dereference() const {
0530             return Mesh::ControlPointIndex::controlPoint(m_mesh->node(m_col, m_row), Mesh::ControlType(m_controlIndex));
0531         }
0532 
0533     private:
0534         MeshType* m_mesh;
0535         int m_col;
0536         int m_row;
0537         int m_controlIndex;
0538     };
0539 
0540     template<bool is_const>
0541     class segment_iterator_impl :
0542         public boost::iterator_facade <segment_iterator_impl<is_const>,
0543                                        Mesh::SegmentIndex,
0544                                        boost::bidirectional_traversal_tag,
0545                                        Mesh::SegmentIndex>
0546     {
0547         using PointType = std::add_const_if_t<is_const, QPointF>;
0548         using NodeType = std::add_const_if_t<is_const, Node>;
0549         using MeshType = std::add_const_if_t<is_const, Mesh>;
0550         using ControlPointIteratorType = control_point_iterator_impl<is_const>;
0551 
0552     public:
0553         segment_iterator_impl()
0554             : m_mesh(0),
0555               m_col(0),
0556               m_row(0),
0557               m_isHorizontal(0)
0558         {}
0559 
0560         segment_iterator_impl(MeshType* mesh, int col, int row, int isHorizontal)
0561             : m_mesh(mesh),
0562               m_col(col),
0563               m_row(row),
0564               m_isHorizontal(isHorizontal)
0565         {
0566         }
0567 
0568         Mesh::SegmentIndex segmentIndex() const {
0569             return
0570                  { Mesh::NodeIndex(m_col, m_row),
0571                    m_isHorizontal};
0572         }
0573 
0574         Mesh::NodeIndex firstNodeIndex() const {
0575             return Mesh::NodeIndex(m_col, m_row);
0576         }
0577 
0578         Mesh::NodeIndex secondNodeIndex() const {
0579             return m_isHorizontal ? Mesh::NodeIndex(m_col + 1, m_row) : Mesh::NodeIndex(m_col, m_row + 1);
0580         }
0581 
0582         NodeType& firstNode() const {
0583             return m_mesh->node(firstNodeIndex());
0584         }
0585 
0586         NodeType& secondNode() const {
0587             return m_mesh->node(secondNodeIndex());
0588         }
0589 
0590         PointType& p0() const {
0591             return firstNode().node;
0592         }
0593 
0594         PointType& p1() const {
0595             return m_isHorizontal ? firstNode().rightControl : firstNode().bottomControl;
0596         }
0597 
0598         PointType& p2() const {
0599             return m_isHorizontal ? secondNode().leftControl : secondNode().topControl;
0600         }
0601 
0602         PointType& p3() const {
0603             return secondNode().node;
0604         }
0605 
0606         ControlPointIteratorType itP0() const {
0607             return m_mesh->find(ControlPointIndex(firstNodeIndex(), Mesh::ControlType::Node));
0608         }
0609 
0610         ControlPointIteratorType itP1() const {
0611             return m_mesh->find(ControlPointIndex(firstNodeIndex(),
0612                                                   m_isHorizontal ?
0613                                                       Mesh::ControlType::RightControl :
0614                                                       Mesh::ControlType::BottomControl));
0615         }
0616 
0617         ControlPointIteratorType itP2() const {
0618             return m_mesh->find(ControlPointIndex(secondNodeIndex(),
0619                                                   m_isHorizontal ?
0620                                                       Mesh::ControlType::LeftControl :
0621                                                       Mesh::ControlType::TopControl));
0622         }
0623 
0624         ControlPointIteratorType itP3() const {
0625             return m_mesh->find(ControlPointIndex(secondNodeIndex(), Mesh::ControlType::Node));
0626         }
0627 
0628         QPointF pointAtParam(qreal t) const {
0629             return KisBezierUtils::bezierCurve(p0(), p1(), p2(), p3(), t);
0630         }
0631 
0632         qreal length() const {
0633             const qreal eps = 1e-3;
0634             return KisBezierUtils::curveLength(p0(), p1(), p2(), p3(), eps);
0635         }
0636 
0637         int degree() const {
0638             return KisBezierUtils::bezierDegree(p0(), p1(), p2(), p3());
0639         }
0640 
0641         bool isHorizontal() const {
0642             return m_isHorizontal;
0643         }
0644 
0645         bool isValid() const {
0646             return nodeIsValid() && controlIsValid();
0647         }
0648 
0649     private:
0650         friend class boost::iterator_core_access;
0651 
0652         bool nodeIsValid() const {
0653             return m_col >= 0 && m_row >= 0 && m_col < m_mesh->size().width() && m_row < m_mesh->size().height();
0654         }
0655 
0656         bool controlIsValid() const {
0657             if (m_col == m_mesh->m_size.width() - 1 && m_isHorizontal) {
0658                 return false;
0659             }
0660 
0661             if (m_row == m_mesh->m_size.height() - 1 && !m_isHorizontal) {
0662                 return false;
0663             }
0664 
0665             return true;
0666         }
0667 
0668         void increment() {
0669             do {
0670                 m_isHorizontal++;
0671                 if (m_isHorizontal > 1) {
0672                     m_isHorizontal = 0;
0673                     m_col++;
0674                     if (m_col >= m_mesh->m_size.width()) {
0675                         m_col = 0;
0676                         m_row++;
0677                     }
0678                 }
0679             } while (nodeIsValid() && !controlIsValid());
0680         }
0681 
0682         void decrement() {
0683             do {
0684                 m_isHorizontal--;
0685                 if (m_isHorizontal < 0) {
0686                     m_isHorizontal = 1;
0687                     m_col--;
0688                     if (m_col < 0) {
0689                         m_col = m_mesh->m_size.width() - 1;
0690                         m_row--;
0691                     }
0692                 }
0693             } while (nodeIsValid() && !controlIsValid());
0694         }
0695 
0696 
0697         bool equal(segment_iterator_impl const& other) const {
0698             return m_isHorizontal == other.m_isHorizontal &&
0699                 m_row == other.m_row &&
0700                 m_col == other.m_col &&
0701                 m_mesh == other.m_mesh;
0702         }
0703 
0704         Mesh::SegmentIndex dereference() const {
0705             return segmentIndex();
0706         }
0707 
0708     private:
0709 
0710         MeshType* m_mesh;
0711         int m_col;
0712         int m_row;
0713         int m_isHorizontal;
0714     };
0715 
0716 public:
0717     Mesh()
0718         : Mesh(QRectF(0.0, 0.0, 1.0, 1.0))
0719     {
0720     }
0721 
0722     Mesh(const QRectF &mapRect, const QSize &size = QSize(2,2))
0723         : m_size(size),
0724           m_originalRect(mapRect)
0725     {
0726         const qreal xControlOffset = 0.2 * (mapRect.width() / size.width());
0727         const qreal yControlOffset = 0.2 * (mapRect.height() / size.height());
0728 
0729         for (int row = 0; row < m_size.height(); row++) {
0730             const qreal yPos = qreal(row) / (size.height() - 1) * mapRect.height() + mapRect.y();
0731 
0732             for (int col = 0; col < m_size.width(); col++) {
0733                 const qreal xPos = qreal(col) / (size.width() - 1) * mapRect.width() + mapRect.x();
0734 
0735                 Node node(QPointF(xPos, yPos));
0736                 node.setLeftControlRelative(QPointF(-xControlOffset, 0));
0737                 node.setRightControlRelative(QPointF(xControlOffset, 0));
0738                 node.setTopControlRelative(QPointF(0, -yControlOffset));
0739                 node.setBottomControlRelative(QPointF(0, yControlOffset));
0740 
0741                 m_nodes.push_back(node);
0742             }
0743         }
0744 
0745         for (int col = 0; col < m_size.width(); col++) {
0746             m_columns.push_back(qreal(col) / (size.width() - 1));
0747         }
0748 
0749         for (int row = 0; row < m_size.height(); row++) {
0750             m_rows.push_back(qreal(row) / (size.height() - 1));
0751         }
0752     }
0753 
0754     bool operator==(const Mesh &rhs) const {
0755         return m_size == rhs.m_size &&
0756                 m_rows == rhs.m_rows &&
0757                 m_columns == rhs.m_columns &&
0758                 m_originalRect == rhs.m_originalRect &&
0759                 m_nodes == rhs.m_nodes;
0760     }
0761 
0762     Node& node(int col, int row) {
0763         KIS_ASSERT(col >= 0 && col < m_size.width() && row >= 0 && row < m_size.height());
0764         return m_nodes[row * m_size.width() + col];
0765     }
0766 
0767     const Node& node(int col, int row) const {
0768         KIS_ASSERT(col >= 0 && col < m_size.width() && row >= 0 && row < m_size.height());
0769         return m_nodes[row * m_size.width() + col];
0770     }
0771 
0772     Node& node(const NodeIndex &index) {
0773         return node(index.x(), index.y());
0774     }
0775 
0776     const Node& node(const NodeIndex &index) const {
0777         return node(index.x(), index.y());
0778     }
0779 
0780 
0781     int subdivideRow(qreal proportionalT) {
0782         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(proportionalT >= 0.0 && proportionalT <= 1.0, -1);
0783 
0784         {
0785             auto existing = std::find(m_rows.begin(), m_rows.end(), proportionalT);
0786             if (existing != m_rows.end()) {
0787                 return distance(m_rows.begin(), existing);
0788             }
0789         }
0790 
0791         const auto it = prev(upper_bound(m_rows.begin(), m_rows.end(), proportionalT));
0792         const int topRow = distance(m_rows.begin(), it);
0793         const qreal relT = (proportionalT - *it) / (*next(it) - *it);
0794 
0795         return subdivideRow(topRow, relT);
0796     }
0797 
0798     int subdivideRow(int topRow, qreal relProportionalT) {
0799         const auto it = m_rows.begin() + topRow;
0800         const int bottomRow = topRow + 1;
0801         const qreal absProportionalT = KisAlgebra2D::lerp(*it, *next(it), relProportionalT);
0802 
0803         std::vector<Node> newRow;
0804         newRow.resize(m_size.width());
0805         for (int col = 0; col < m_size.width(); col++) {
0806             const qreal t =
0807                 KisBezierUtils::curveParamByProportion(node(col, topRow).node,
0808                                                        node(col, topRow).bottomControl,
0809                                                        node(col, bottomRow).topControl,
0810                                                        node(col, bottomRow).node,
0811                                                        relProportionalT,
0812                                                        0.01);
0813 
0814             splitCurveVertically(node(col, topRow), node(col, bottomRow), t, newRow[col]);
0815         }
0816 
0817         m_nodes.insert(m_nodes.begin() + bottomRow * m_size.width(),
0818                        newRow.begin(), newRow.end());
0819 
0820         m_size.rheight()++;
0821         auto insertedIt = m_rows.insert(next(it), absProportionalT);
0822         return distance(m_rows.begin(), insertedIt);
0823     }
0824 
0825     int subdivideColumn(qreal proportionalT) {
0826         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(proportionalT >= 0.0 && proportionalT <= 1.0, -1);
0827 
0828         {
0829             auto existing = std::find(m_columns.begin(), m_columns.end(), proportionalT);
0830             if (existing != m_columns.end()) {
0831                 return distance(m_columns.begin(), existing);
0832             }
0833         }
0834 
0835         const auto it = prev(upper_bound(m_columns.begin(), m_columns.end(), proportionalT));
0836         const int leftColumn = distance(m_columns.begin(), it);
0837 
0838         const qreal relT = (proportionalT - *it) / (*next(it) - *it);
0839 
0840         return subdivideColumn(leftColumn, relT);
0841     }
0842 
0843     int subdivideColumn(int leftColumn, qreal relProportionalT) {
0844         const auto it = m_columns.begin() + leftColumn;
0845         const int rightColumn = leftColumn + 1;
0846         const qreal absProportinalT = KisAlgebra2D::lerp(*it, *next(it), relProportionalT);
0847 
0848         std::vector<Node> newColumn;
0849         newColumn.resize(m_size.height());
0850         for (int row = 0; row < m_size.height(); row++) {
0851             const qreal t =
0852                 KisBezierUtils::curveParamByProportion(node(leftColumn, row).node,
0853                                                        node(leftColumn, row).rightControl,
0854                                                        node(rightColumn, row).leftControl,
0855                                                        node(rightColumn, row).node,
0856                                                        relProportionalT,
0857                                                        0.01);
0858 
0859             splitCurveHorizontally(node(leftColumn, row), node(rightColumn, row), t, newColumn[row]);
0860         }
0861 
0862         auto dstIt = m_nodes.begin() + rightColumn;
0863         for (auto columnIt = newColumn.begin(); columnIt != newColumn.end(); ++columnIt) {
0864             dstIt = m_nodes.insert(dstIt, *columnIt);
0865             dstIt += m_size.width() + 1;
0866         }
0867 
0868         m_size.rwidth()++;
0869         auto insertedIt = m_columns.insert(next(it), absProportinalT);
0870         return distance(m_columns.begin(), insertedIt);
0871     }
0872 
0873     void removeColumn(int column) {
0874         const bool hasNeighbours = column > 0 || column < m_size.width() - 1;
0875 
0876         if (hasNeighbours) {
0877             for (int row = 0; row < m_size.height(); row++) {
0878                 unlinkNodeHorizontally(node(column - 1, row), node(column, row), node(column + 1, row));
0879             }
0880         }
0881 
0882         auto it = m_nodes.begin() + column;
0883         for (int row = 0; row < m_size.height(); row++) {
0884             it = m_nodes.erase(it);
0885             it += m_size.width() - 1;
0886         }
0887 
0888         m_size.rwidth()--;
0889         m_columns.erase(m_columns.begin() + column);
0890     }
0891 
0892     void removeRow(int row) {
0893         const bool hasNeighbours = row > 0 || row < m_size.height() - 1;
0894 
0895         if (hasNeighbours) {
0896             for (int column = 0; column < m_size.width(); column++) {
0897                 unlinkNodeVertically(node(column, row - 1), node(column, row), node(column, row + 1));
0898             }
0899         }
0900 
0901         auto it = m_nodes.begin() + row * m_size.width();
0902         m_nodes.erase(it, it + m_size.width());
0903 
0904         m_size.rheight()--;
0905         m_rows.erase(m_rows.begin() + row);
0906     }
0907 
0908     void removeColumnOrRow(NodeIndex index, bool row) {
0909         if (row) {
0910             removeRow(index.y());
0911         } else {
0912             removeColumn(index.x());
0913         }
0914     }
0915 
0916     void subdivideSegment(SegmentIndex index, qreal proportionalT) {
0917         auto it = find(index);
0918         KIS_SAFE_ASSERT_RECOVER_RETURN(it != endSegments());
0919 
0920         if (it.isHorizontal()) {
0921             subdivideColumn(it.firstNodeIndex().x(), proportionalT);
0922         } else {
0923             subdivideRow(it.firstNodeIndex().y(), proportionalT);
0924         }
0925     }
0926 
0927     Patch makePatch(const PatchIndex &index) const {
0928         return makePatch(index.x(), index.y());
0929     }
0930 
0931     Patch makePatch(int col, int row) const
0932     {
0933         const Node &tl = node(col, row);
0934         const Node &tr = node(col + 1, row);
0935         const Node &bl = node(col, row + 1);
0936         const Node &br = node(col + 1, row + 1);
0937 
0938         Patch patch;
0939 
0940         patch.points[Patch::TL] = tl.node;
0941         patch.points[Patch::TL_HC] = tl.rightControl;
0942         patch.points[Patch::TL_VC] = tl.bottomControl;
0943 
0944         patch.points[Patch::TR] = tr.node;
0945         patch.points[Patch::TR_HC] = tr.leftControl;
0946         patch.points[Patch::TR_VC] = tr.bottomControl;
0947 
0948         patch.points[Patch::BL] = bl.node;
0949         patch.points[Patch::BL_HC] = bl.rightControl;
0950         patch.points[Patch::BL_VC] = bl.topControl;
0951 
0952         patch.points[Patch::BR] = br.node;
0953         patch.points[Patch::BR_HC] = br.leftControl;
0954         patch.points[Patch::BR_VC] = br.topControl;
0955 
0956         const QRectF relRect(m_columns[col],
0957                              m_rows[row],
0958                              m_columns[col + 1] - m_columns[col],
0959                              m_rows[row + 1] - m_rows[row]);
0960 
0961         assignPatchData(&patch, KisAlgebra2D::relativeToAbsolute(relRect, m_originalRect),
0962                         tl, tr, bl, br);
0963 
0964         return patch;
0965     }
0966 
0967     using patch_iterator = patch_iterator_impl<false>;
0968     using patch_const_iterator = patch_iterator_impl<true>;
0969 
0970     using control_point_iterator = control_point_iterator_impl<false>;
0971     using control_point_const_iterator = control_point_iterator_impl<true>;
0972 
0973     using segment_iterator = segment_iterator_impl<false>;
0974     using segment_const_iterator = segment_iterator_impl<true>;
0975 
0976     patch_iterator beginPatches() { return beginPatches(*this); }
0977     patch_const_iterator beginPatches() const { return beginPatches(*this); }
0978     patch_const_iterator constBeginPatches() const { return beginPatches(*this); }
0979 
0980     patch_iterator endPatches() { return endPatches(*this); }
0981     patch_const_iterator endPatches() const { return endPatches(*this); }
0982     patch_const_iterator constEndPatches() const { return endPatches(*this); }
0983 
0984     control_point_iterator beginControlPoints() { return beginControlPoints(*this); }
0985     control_point_const_iterator beginControlPoints() const { return beginControlPoints(*this); }
0986     control_point_const_iterator constBeginControlPoints() const { return beginControlPoints(*this); }
0987 
0988     control_point_iterator endControlPoints() { return endControlPoints(*this); }
0989     control_point_const_iterator endControlPoints() const { return endControlPoints(*this); }
0990     control_point_const_iterator constEndControlPoints() const { return endControlPoints(*this); }
0991 
0992     segment_iterator beginSegments() { return beginSegments(*this); }
0993     segment_const_iterator beginSegments() const { return beginSegments(*this); }
0994     segment_const_iterator constBeginSegments() const { return beginSegments(*this); }
0995 
0996     segment_iterator endSegments() { return endSegments(*this); }
0997     segment_const_iterator endSegments() const {  return endSegments(*this); }
0998     segment_const_iterator constEndSegments() const { return endSegments(*this); }
0999 
1000     control_point_iterator find(const ControlPointIndex &index) { return find(*this, index); }
1001     control_point_const_iterator find(const ControlPointIndex &index) const { return find(*this, index); }
1002     control_point_const_iterator constFind(const ControlPointIndex &index) const { return find(*this, index); }
1003 
1004     control_point_iterator find(const NodeIndex &index) { return find(*this, index); }
1005     control_point_const_iterator find(const NodeIndex &index) const { return find(*this, index); }
1006     control_point_const_iterator constFind(const NodeIndex &index) const { return find(*this, index); }
1007 
1008     segment_iterator find(const SegmentIndex &index) { return find(*this, index); }
1009     segment_const_iterator find(const SegmentIndex &index) const { return find(*this, index); }
1010     segment_const_iterator constFind(const SegmentIndex &index) const { return find(*this, index); }
1011 
1012     patch_iterator find(const PatchIndex &index) { return find(*this, index); }
1013     patch_const_iterator find(const PatchIndex &index) const { return find(*this, index); }
1014     patch_const_iterator constFind(const PatchIndex &index) const { return find(*this, index); }
1015 
1016     QSize size() const {
1017         return m_size;
1018     }
1019 
1020     QRectF originalRect() const {
1021         return m_originalRect;
1022     }
1023 
1024     QRectF dstBoundingRect() const {
1025         QRectF result;
1026         for (auto it = beginPatches(); it != endPatches(); ++it) {
1027             result |= it->dstBoundingRect();
1028         }
1029         return result;
1030     }
1031 
1032     bool isIdentity() const {
1033         Mesh identityMesh(m_originalRect, m_size);
1034         return *this == identityMesh;
1035     }
1036 
1037     void translate(const QPointF &offset) {
1038         for (auto it = m_nodes.begin(); it != m_nodes.end(); ++it) {
1039             it->translate(offset);
1040         }
1041     }
1042 
1043     void transform(const QTransform &t) {
1044         for (auto it = m_nodes.begin(); it != m_nodes.end(); ++it) {
1045             it->transform(t);
1046         }
1047     }
1048 
1049     void transformSrcAndDst(const QTransform &t) {
1050         KIS_SAFE_ASSERT_RECOVER_RETURN(t.type() <= QTransform::TxScale);
1051         transform(t);
1052         m_originalRect = t.mapRect(m_originalRect);
1053     }
1054 
1055     ControlPointIndex hitTestNode(const QPointF &pt, qreal distanceThreshold) const {
1056         return hitTestPointImpl(pt, distanceThreshold, true);
1057     }
1058 
1059     ControlPointIndex hitTestControlPoint(const QPointF &pt, qreal distanceThreshold) const {
1060         return hitTestPointImpl(pt, distanceThreshold, false);
1061     }
1062 
1063     SegmentIndex hitTestSegment(const QPointF &pt, qreal distanceThreshold, qreal *t = 0) const {
1064         auto result = endSegments();
1065         qreal minDistance = std::numeric_limits<qreal>::max();
1066 
1067         for (auto it = beginSegments(); it != endSegments(); ++it) {
1068 
1069             qreal foundDistance = 0.0;
1070             const qreal foundT = KisBezierUtils::nearestPoint({it.p0(), it.p1(), it.p2(), it.p3()}, pt, &foundDistance);
1071 
1072             if (foundDistance < minDistance && foundDistance < distanceThreshold) {
1073                 result = it;
1074                 minDistance = foundDistance;
1075                 if (t) {
1076                     *t = foundT;
1077                 }
1078             }
1079         }
1080 
1081         return result.segmentIndex();
1082     }
1083 
1084     template <typename T>
1085     bool isIndexValid(const T &index) const {
1086         return find(index).isValid();
1087     }
1088 
1089     void reshapeMeshHorizontally(int numColumns) {
1090         KIS_SAFE_ASSERT_RECOVER_RETURN(numColumns >= 2);
1091 
1092         std::vector<int> insertedIndexes;
1093 
1094         for (int i = 1; i < numColumns - 1; i++) {
1095             const qreal pos = qreal(i) / (numColumns - 1);
1096             int inserted = subdivideColumn(pos);
1097             KIS_SAFE_ASSERT_RECOVER(inserted >= 0) { continue; }
1098 
1099             insertedIndexes.push_back(inserted);
1100         }
1101 
1102         for (int i = m_columns.size() - 2; i >= 1; i--) {
1103             if (std::find(insertedIndexes.begin(), insertedIndexes.end(), i) == insertedIndexes.end()) {
1104                 removeColumn(i);
1105             }
1106         }
1107     }
1108 
1109     void reshapeMeshVertically(int numRows) {
1110         KIS_SAFE_ASSERT_RECOVER_RETURN(numRows >= 2);
1111 
1112         std::vector<int> insertedIndexes;
1113 
1114         for (int i = 1; i < numRows - 1; i++) {
1115             const qreal pos = qreal(i) / (numRows - 1);
1116             int inserted = subdivideRow(pos);
1117             KIS_SAFE_ASSERT_RECOVER(inserted >= 0) { continue; }
1118 
1119             insertedIndexes.push_back(inserted);
1120         }
1121 
1122         for (int i = m_rows.size() - 2; i >= 1; i--) {
1123             if (std::find(insertedIndexes.begin(), insertedIndexes.end(), i) == insertedIndexes.end()) {
1124                 removeRow(i);
1125             }
1126         }
1127     }
1128 
1129 private:
1130     void splitCurveHorizontally(Node &left, Node &right, qreal t, Node &newNode) {
1131         using KisBezierUtils::deCasteljau;
1132         using KisAlgebra2D::lerp;
1133 
1134         QPointF p1, p2, p3, q1, q2;
1135 
1136         deCasteljau(left.node, left.rightControl, right.leftControl, right.node, t,
1137                     &p1, &p2, &p3, &q1, &q2);
1138 
1139         left.rightControl = p1;
1140         newNode.leftControl = p2;
1141         newNode.node = p3;
1142         newNode.rightControl = q1;
1143         right.leftControl = q2;
1144 
1145         newNode.topControl = newNode.node + lerp(left.topControl - left.node, right.topControl - right.node, t);
1146         newNode.bottomControl = newNode.node + lerp(left.bottomControl - left.node, right.bottomControl - right.node, t);
1147 
1148         lerpNodeData(left, right, t, newNode);
1149     }
1150 
1151     void splitCurveVertically(Node &top, Node &bottom, qreal t, Node &newNode) {
1152         using KisBezierUtils::deCasteljau;
1153         using KisAlgebra2D::lerp;
1154 
1155         QPointF p1, p2, p3, q1, q2;
1156 
1157         deCasteljau(top.node, top.bottomControl, bottom.topControl, bottom.node, t,
1158                     &p1, &p2, &p3, &q1, &q2);
1159 
1160         top.bottomControl = p1;
1161         newNode.topControl = p2;
1162         newNode.node = p3;
1163         newNode.bottomControl = q1;
1164         bottom.topControl = q2;
1165 
1166         newNode.leftControl = newNode.node + lerp(top.leftControl - top.node, bottom.leftControl - bottom.node, t);
1167         newNode.rightControl = newNode.node + lerp(top.rightControl - top.node, bottom.rightControl - bottom.node, t);
1168 
1169         lerpNodeData(top, bottom, t, newNode);
1170     }
1171 
1172     void unlinkNodeHorizontally(Mesh::Node &left, const Mesh::Node &node, Mesh::Node &right)
1173     {
1174         std::tie(left.rightControl, right.leftControl) =
1175             KisBezierUtils::removeBezierNode(left.node, left.rightControl,
1176                                              node.leftControl, node.node, node.rightControl,
1177                                              right.leftControl, right.node);
1178     }
1179 
1180     void unlinkNodeVertically(Mesh::Node &top, const Mesh::Node &node, Mesh::Node &bottom)
1181     {
1182         std::tie(top.bottomControl, bottom.topControl) =
1183             KisBezierUtils::removeBezierNode(top.node, top.bottomControl,
1184                                              node.topControl, node.node, node.bottomControl,
1185                                              bottom.topControl, bottom.node);
1186     }
1187 
1188     ControlPointIndex hitTestPointImpl(const QPointF &pt, qreal distanceThreshold, bool onlyNodeMode) const {
1189         const qreal distanceThresholdSq = pow2(distanceThreshold);
1190 
1191         auto result = endControlPoints();
1192         qreal minDistanceSq = std::numeric_limits<qreal>::max();
1193 
1194         for (auto it = beginControlPoints(); it != endControlPoints(); ++it) {
1195             if (onlyNodeMode != (it.type() == ControlType::Node)) continue;
1196 
1197             const qreal distSq = kisSquareDistance(*it, pt);
1198             if (distSq < minDistanceSq && distSq < distanceThresholdSq) {
1199                 result = it;
1200                 minDistanceSq = distSq;
1201             }
1202         }
1203 
1204         return result.controlIndex();
1205     }
1206 
1207 private:
1208     template <class MeshType,
1209               class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1210     static
1211     IteratorType find(MeshType &mesh, const ControlPointIndex &index) {
1212         IteratorType it(&mesh, index.nodeIndex.x(), index.nodeIndex.y(), index.controlType);
1213         return it.isValid() ? it : mesh.endControlPoints();
1214     }
1215 
1216     template <class MeshType,
1217               class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1218     static
1219     IteratorType find(MeshType &mesh, const NodeIndex &index) {
1220         IteratorType it(&mesh, index.x(), index.y(), Mesh::ControlType::Node);
1221         return it.isValid() ? it : mesh.endControlPoints();
1222     }
1223 
1224     template <class MeshType,
1225               class IteratorType = segment_iterator_impl<std::is_const<MeshType>::value>>
1226     static
1227     IteratorType find(MeshType &mesh, const SegmentIndex &index) {
1228         IteratorType it(&mesh, index.first.x(), index.first.y(), index.second);
1229         return it.isValid() ? it : mesh.endSegments();
1230     }
1231 
1232     template <class MeshType,
1233               class IteratorType = patch_iterator_impl<std::is_const<MeshType>::value>>
1234     static
1235     IteratorType find(MeshType &mesh, const PatchIndex &index) {
1236         IteratorType it(&mesh, index.x(), index.y());
1237         return it.isValid() ? it : mesh.endPatches();
1238     }
1239 
1240     template <class MeshType,
1241               class IteratorType = patch_iterator_impl<std::is_const<MeshType>::value>>
1242     static
1243     IteratorType beginPatches(MeshType &mesh) {
1244         return IteratorType(&mesh, 0, 0);
1245     }
1246 
1247     template <class MeshType,
1248               class IteratorType = patch_iterator_impl<std::is_const<MeshType>::value>>
1249     static
1250     IteratorType endPatches(MeshType &mesh) {
1251         return IteratorType(&mesh, 0, mesh.m_size.height() - 1);
1252     }
1253 
1254     template <class MeshType,
1255               class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1256     static
1257     IteratorType beginControlPoints(MeshType &mesh) {
1258         return IteratorType(&mesh, 0, 0, ControlType::RightControl);
1259     }
1260 
1261     template <class MeshType,
1262               class IteratorType = control_point_iterator_impl<std::is_const<MeshType>::value>>
1263     static
1264     IteratorType endControlPoints(MeshType &mesh) {
1265         return IteratorType(&mesh, 0, mesh.m_size.height(), 0);
1266     }
1267 
1268     template <class MeshType,
1269               class IteratorType = segment_iterator_impl<std::is_const<MeshType>::value>>
1270     static
1271     IteratorType beginSegments(MeshType &mesh) {
1272         return IteratorType(&mesh, 0, 0, 0);
1273     }
1274 
1275     template <class MeshType,
1276               class IteratorType = segment_iterator_impl<std::is_const<MeshType>::value>>
1277     static
1278     IteratorType endSegments(MeshType &mesh) {
1279         return IteratorType(&mesh, 0, mesh.m_size.height(), 0);
1280     }
1281 
1282 protected:
1283 
1284     std::vector<Node> m_nodes;
1285     std::vector<qreal> m_rows;
1286     std::vector<qreal> m_columns;
1287 
1288     QSize m_size;
1289     QRectF m_originalRect;
1290 };
1291 
1292 template<typename Node, typename Patch>
1293 QDebug operator<<(QDebug dbg, const Mesh<Node, Patch> &mesh)
1294 {
1295     dbg.nospace() << "Mesh " << mesh.size() << "\n";
1296 
1297     for (int y = 0; y < mesh.size().height(); y++) {
1298         for (int x = 0; x < mesh.size().width(); x++) {
1299             dbg.nospace() << "    node(" << x << ", " << y << ") " << mesh.node(x, y) << "\n";
1300         }
1301     }
1302     return dbg.space();
1303 }
1304 
1305 template<typename NodeArg, typename PatchArg>
1306 template<bool is_const>
1307 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType
1308 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::segmentP() const
1309 {
1310     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType;
1311     return SegmentIteratorType(m_mesh, m_col, m_row, 1);
1312 }
1313 
1314 template<typename NodeArg, typename PatchArg>
1315 template<bool is_const>
1316 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType
1317 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::segmentQ() const
1318 {
1319     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType;
1320     return SegmentIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col, m_row + 1, 1);
1321 }
1322 
1323 template<typename NodeArg, typename PatchArg>
1324 template<bool is_const>
1325 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType
1326 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::segmentR() const
1327 {
1328     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType;
1329     return SegmentIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col, m_row, 0);
1330 }
1331 
1332 template<typename NodeArg, typename PatchArg>
1333 template<bool is_const>
1334 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType
1335 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::segmentS() const
1336 {
1337     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::SegmentIteratorType;
1338     return SegmentIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col + 1, m_row, 0);
1339 }
1340 
1341 template<typename NodeArg, typename PatchArg>
1342 template<bool is_const>
1343 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType
1344 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::nodeTopLeft() const
1345 {
1346     using ControlPointIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType;
1347     return ControlPointIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col, m_row, Mesh::ControlType::Node);
1348 }
1349 
1350 template<typename NodeArg, typename PatchArg>
1351 template<bool is_const>
1352 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType
1353 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::nodeTopRight() const
1354 {
1355     using ControlPointIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType;
1356     return ControlPointIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col + 1, m_row, Mesh::ControlType::Node);
1357 }
1358 
1359 template<typename NodeArg, typename PatchArg>
1360 template<bool is_const>
1361 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType
1362 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::nodeBottomLeft() const
1363 {
1364     using ControlPointIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType;
1365     return ControlPointIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col, m_row + 1, Mesh::ControlType::Node);
1366 }
1367 
1368 template<typename NodeArg, typename PatchArg>
1369 template<bool is_const>
1370 typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType
1371 Mesh<NodeArg, PatchArg>::patch_iterator_impl<is_const>::nodeBottomRight() const
1372 {
1373     using ControlPointIteratorType = typename Mesh<NodeArg, PatchArg>::template patch_iterator_impl<is_const>::ControlPointIteratorType;
1374     return ControlPointIteratorType(const_cast<Mesh<NodeArg, PatchArg>*>(m_mesh), m_col + 1, m_row + 1, Mesh::ControlType::Node);
1375 }
1376 
1377 
1378 template<typename NodeArg, typename PatchArg>
1379 template<bool is_const>
1380 typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType
1381 Mesh<NodeArg, PatchArg>::control_point_iterator_impl<is_const>::topSegment() const
1382 {
1383     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType;
1384 
1385     if (isTopBorder()) {
1386         return m_mesh->endSegments();
1387     }
1388 
1389     return SegmentIteratorType(m_mesh, m_col, m_row - 1, false);
1390 }
1391 
1392 template<typename NodeArg, typename PatchArg>
1393 template<bool is_const>
1394 typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType
1395 Mesh<NodeArg, PatchArg>::control_point_iterator_impl<is_const>::bottomSegment() const
1396 {
1397     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType;
1398 
1399     if (isBottomBorder()) {
1400         return m_mesh->endSegments();
1401     }
1402 
1403     return SegmentIteratorType(m_mesh, m_col, m_row, false);
1404 }
1405 
1406 template<typename NodeArg, typename PatchArg>
1407 template<bool is_const>
1408 typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType
1409 Mesh<NodeArg, PatchArg>::control_point_iterator_impl<is_const>::leftSegment() const
1410 {
1411     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType;
1412 
1413     if (isLeftBorder()) {
1414         return m_mesh->endSegments();
1415     }
1416 
1417     return SegmentIteratorType(m_mesh, m_col - 1, m_row, true);
1418 }
1419 
1420 template<typename NodeArg, typename PatchArg>
1421 template<bool is_const>
1422 typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType
1423 Mesh<NodeArg, PatchArg>::control_point_iterator_impl<is_const>::rightSegment() const
1424 {
1425     using SegmentIteratorType = typename Mesh<NodeArg, PatchArg>::template control_point_iterator_impl<is_const>::SegmentIteratorType;
1426 
1427     if (isRightBorder()) {
1428         return m_mesh->endSegments();
1429     }
1430 
1431     return SegmentIteratorType(m_mesh, m_col, m_row, true);
1432 }
1433 
1434 enum SmartMoveMeshControlMode {
1435     MoveFree,
1436     MoveSymmetricLock,
1437     MoveRotationLock
1438 };
1439 
1440 template<typename NodeArg, typename PatchArg>
1441 void smartMoveControl(Mesh<NodeArg, PatchArg> &mesh,
1442                       typename Mesh<NodeArg, PatchArg>::ControlPointIndex index,
1443                       const QPointF &move,
1444                       SmartMoveMeshControlMode mode,
1445                       bool scaleNodeMoves)
1446 {
1447     using ControlType = typename Mesh<NodeArg, PatchArg>::ControlType;
1448     using ControlPointIndex = typename Mesh<NodeArg, PatchArg>::ControlPointIndex;
1449 //    using ControlPointIterator = typename Mesh<NodeArg, PatchArg>::control_point_iterator;
1450     using SegmentIterator = typename Mesh<NodeArg, PatchArg>::segment_iterator;
1451 
1452     auto it = mesh.find(index);
1453     KIS_SAFE_ASSERT_RECOVER_RETURN(it != mesh.endControlPoints());
1454 
1455     if (it.isNode()) {
1456         auto preAdjustSegment = [] (Mesh<NodeArg, PatchArg> &mesh,
1457                                     SegmentIterator it,
1458                                     const QPointF &normalizedOffset) {
1459 
1460             if (it == mesh.endSegments()) return;
1461 
1462             const QPointF base1 = it.p3() - it.p0();
1463             const QPointF base2 = it.p3() - it.p0() - normalizedOffset;
1464 
1465             {
1466                 const QPointF control = it.p1() - it.p0();
1467                 const qreal dist0 = KisAlgebra2D::norm(base1);
1468                 const qreal dist1 = KisAlgebra2D::dotProduct(base2, base1) / dist0;
1469                 const qreal coeff = dist1 / dist0;
1470 
1471                 it.p1() = it.p0() + coeff * (control);
1472             }
1473             {
1474                 const QPointF control = it.p2() - it.p3();
1475                 const qreal dist0 = KisAlgebra2D::norm(base1);
1476                 const qreal dist1 = KisAlgebra2D::dotProduct(base2, base1) / dist0;
1477                 const qreal coeff = dist1 / dist0;
1478 
1479                 it.p2() = it.p3() + coeff * (control);
1480             }
1481         };
1482 
1483         if (scaleNodeMoves) {
1484             preAdjustSegment(mesh, it.topSegment(), -move);
1485             preAdjustSegment(mesh, it.leftSegment(), -move);
1486             preAdjustSegment(mesh, it.bottomSegment(), move);
1487             preAdjustSegment(mesh, it.rightSegment(), move);
1488         }
1489 
1490         it.node().translate(move);
1491 
1492     } else {
1493         const QPointF newPos = *it + move;
1494 
1495         if (mode == MoveRotationLock || mode == MoveSymmetricLock) {
1496             const qreal rotation = KisAlgebra2D::angleBetweenVectors(*it - it.node().node,
1497                                                                      newPos - it.node().node);
1498             QTransform R;
1499             R.rotateRadians(rotation);
1500 
1501             const QTransform t =
1502                     QTransform::fromTranslate(-it.node().node.x(), -it.node().node.y()) *
1503                     R *
1504                     QTransform::fromTranslate(it.node().node.x(), it.node().node.y());
1505 
1506             if (mode == MoveRotationLock) {
1507                 for (int intType = 0; intType < 4; intType++) {
1508                     ControlType type = static_cast<ControlType>(intType);
1509 
1510                     if (type == ControlType::Node ||
1511                             type == index.controlType) {
1512 
1513                         continue;
1514                     }
1515 
1516                     auto neighbourIt = mesh.find(ControlPointIndex(index.nodeIndex, type));
1517                     if (neighbourIt == mesh.endControlPoints()) continue;
1518 
1519                     *neighbourIt = t.map(*neighbourIt);
1520                 }
1521             } else {
1522                 auto neighbourIt = it.symmetricControl();
1523                 if (neighbourIt != mesh.endControlPoints()) {
1524                     *neighbourIt = t.map(*neighbourIt);
1525                 }
1526             }
1527         }
1528 
1529         *it = newPos;
1530     }
1531 }
1532 
1533 KRITAGLOBAL_EXPORT
1534 QDebug operator<<(QDebug dbg, const BaseMeshNode &n);
1535 
1536 KRITAGLOBAL_EXPORT
1537 void saveValue(QDomElement *parent, const QString &tag, const BaseMeshNode &node);
1538 
1539 KRITAGLOBAL_EXPORT
1540 bool loadValue(const QDomElement &parent, BaseMeshNode *node);
1541 
1542 }
1543 
1544 namespace KisDomUtils {
1545 using KisBezierMeshDetails::loadValue;
1546 using KisBezierMeshDetails::saveValue;
1547 }
1548 
1549 template <typename Node, typename Patch>
1550 using KisBezierMeshBase = KisBezierMeshDetails::Mesh<Node, Patch>;
1551 
1552 using KisSmartMoveMeshControlMode = KisBezierMeshDetails::SmartMoveMeshControlMode;
1553 using KisBezierMesh = KisBezierMeshDetails::Mesh<KisBezierMeshDetails::BaseMeshNode, KisBezierPatch>;
1554 
1555 
1556 #endif // KISBEZIERMESH_H