File indexing completed on 2024-06-09 04:20:49

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Sharaf Zaman <sharafzaz121@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #ifndef SVGMESHPATCH_H
0007 #define SVGMESHPATCH_H
0008 
0009 #include <array>
0010 
0011 #include <QColor>
0012 #include <QPointF>
0013 #include <QVector>
0014 #include <QMap>
0015 #include <QScopedPointer>
0016 #include <QPainterPath>
0017 
0018 #include <KoPathShape.h>
0019 
0020 struct SvgMeshStop {
0021     QColor color;
0022     QPointF point;
0023 
0024     SvgMeshStop()
0025     {}
0026 
0027     SvgMeshStop(QColor color, QPointF point)
0028         : color(color), point(point)
0029     {}
0030 
0031     bool isValid() const { return color.isValid(); }
0032 };
0033 
0034 using SvgMeshPath = std::array<QPointF, 4>;
0035 
0036 class KRITAFLAKE_EXPORT SvgMeshPatch
0037 {
0038 public:
0039     /// Position of stop in the patch
0040     enum Type {
0041         Top = 0,
0042         Right,
0043         Bottom,
0044         Left,
0045         Size,
0046     };
0047 
0048     SvgMeshPatch(QPointF startingPoint);
0049     SvgMeshPatch(const SvgMeshPatch& other);
0050 
0051     // NOTE: NO path is created here
0052     // sets a new starting point for the patch
0053     void moveTo(const QPointF& p);
0054     /// Helper to convert to a cubic curve internally.
0055     void lineTo(const QPointF& p);
0056     /// add points as curve.
0057     void curveTo(const QPointF& c1, const QPointF& c2, const QPointF& p);
0058 
0059     /// returns the starting point of the stop
0060     SvgMeshStop getStop(Type type) const;
0061 
0062     /// returns the midPoint in parametric space
0063     inline QPointF getMidpointParametric(Type type) const {
0064         return (m_parametricCoords[type] + m_parametricCoords[(type + 1) % Size]) * 0.5;
0065     }
0066 
0067     /// get the point on a segment using De Casteljau's algorithm
0068     QPointF segmentPointAt(Type type, qreal t) const;
0069 
0070     /// split a segment using De Casteljau's algorithm
0071     QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> segmentSplitAt(Type type, qreal t) const;
0072 
0073     /// Get a segment of the path in the meshpatch
0074     std::array<QPointF, 4> getSegment(Type type) const;
0075 
0076     /// Get full (closed) meshpath
0077     QPainterPath getPath() const;
0078 
0079     /// Get size swept by mesh in pts
0080     QSizeF size() const;
0081 
0082     QRectF boundingRect() const;
0083 
0084     /// Gets the curve passing through the middle of meshpatch
0085     std::array<QPointF, 4> getMidCurve(bool isVertical) const;
0086 
0087     void subdivideHorizontally(QVector<SvgMeshPatch*>& subdivided,
0088                                const QVector<QColor>& colors) const;
0089 
0090     void subdivideVertically(QVector<SvgMeshPatch*>& subdivided,
0091                              const QVector<QColor>& colors) const;
0092 
0093     void subdivide(QVector<SvgMeshPatch*>& subdivided,
0094                    const QVector<QColor>& colors) const;
0095 
0096     bool isDivisibleVertically() const;
0097     bool isDivisibleHorizontally() const;
0098 
0099     int countPoints() const;
0100 
0101     /* Parses raw pathstr and adds path to the shape, if the path isn't
0102      * complete, it will have to be computed and given with pathIncomplete = true
0103      * (Ideal case for std::optional)
0104      */
0105     void addStop(const QString& pathStr, QColor color, Type edge, bool pathIncomplete = false, QPointF lastPoint = QPointF());
0106 
0107     /// Adds path to the shape
0108     void addStop(const std::array<QPointF, 4>& pathPoints, QColor color, Type edge);
0109 
0110     /// Adds linear path to the shape
0111     void addStopLinear(const std::array<QPointF, 2>& pathPoints, QColor color, Type edge);
0112 
0113     void modifyPath(SvgMeshPatch::Type type, std::array<QPointF, 4> newPath);
0114     void modifyCorner(SvgMeshPatch::Type type, const QPointF &delta);
0115 
0116     void setStopColor(SvgMeshPatch::Type type, const QColor &color);
0117 
0118     void setTransform(const QTransform& matrix);
0119 
0120 private:
0121     /* Parses path and adds it to m_path and returns the last point of the curve/line
0122      * see also: SvgMeshPatch::addStop
0123      */
0124     QPointF parseMeshPath(const QString& path, bool pathIncomplete = false, const QPointF lastPoint = QPointF());
0125     const char* getCoord(const char* ptr, qreal& number);
0126 
0127 private:
0128     bool m_newPath;
0129     int counter {0};
0130 
0131     /// This is the starting point for each path
0132     QPointF m_startingPoint;
0133 
0134     std::array<SvgMeshStop, Size> m_nodes;
0135     std::array<std::array<QPointF, 4>, 4> controlPoints;
0136     /// Coordinates in UV space
0137     std::array<QPointF, 4> m_parametricCoords;
0138 };
0139 
0140 #endif // SVGMESHPATCH_H