File indexing completed on 2025-02-02 04:15:57

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISOPTIMIZEDBRUSHOUTLINE_H
0008 #define KISOPTIMIZEDBRUSHOUTLINE_H
0009 
0010 #include <QList>
0011 #include <QPolygonF>
0012 #include <QTransform>
0013 #include <boost/iterator/iterator_facade.hpp>
0014 #include <kritaimage_export.h>
0015 
0016 class QPainterPath;
0017 
0018 /**
0019  * An special class for storing the brush outline
0020  * in an optimized way. It converts the outline into
0021  * the vector of QPolygonF objects right away and avoids
0022  * doing any modifications and/or transformations to it
0023  * until the final stage, when the outline is requested
0024  * to be drawn.
0025  */
0026 class KRITAIMAGE_EXPORT KisOptimizedBrushOutline
0027 {
0028 public:
0029     class KRITAIMAGE_EXPORT const_iterator :
0030         public boost::iterator_facade <const_iterator,
0031                                        QPolygonF,
0032                                        boost::forward_traversal_tag,
0033                                        QPolygonF>
0034     {
0035     public:
0036         const_iterator()
0037             : m_outline(0),
0038               m_index(0) {}
0039 
0040         const_iterator(const KisOptimizedBrushOutline *outline, int index)
0041             : m_outline(outline),
0042               m_index(index) {}
0043 
0044     private:
0045         friend class boost::iterator_core_access;
0046 
0047         void increment() {
0048             m_index++;
0049         }
0050 
0051         bool equal(const_iterator const& other) const {
0052             return m_index == other.m_index &&
0053                 m_outline == other.m_outline;
0054         }
0055 
0056         QPolygonF dereference() const;
0057 
0058     private:
0059         const KisOptimizedBrushOutline *m_outline;
0060         int m_index;
0061     };
0062 
0063 public:
0064     KisOptimizedBrushOutline();
0065     KisOptimizedBrushOutline(const QPainterPath &path);
0066     KisOptimizedBrushOutline(const QVector<QPolygonF> &subpaths);
0067 
0068     QRectF boundingRect() const;
0069 
0070     bool isEmpty() const;
0071 
0072     void addRect(const QRectF &rc);
0073     void addEllipse(const QPointF &center, qreal rx, qreal ry);
0074     void addPath(const QPainterPath &path);
0075     void addPath(const KisOptimizedBrushOutline &path);
0076 
0077     void translate(qreal tx, qreal ty);
0078     void translate(const QPointF &offset);
0079 
0080     /**
0081      * Transforms all the polygons belonging to the outline.
0082      * The transformation is done in optimized way, that is,
0083      * no polygons are transformed until the final iteration
0084      * over them.
0085      */
0086     void map(const QTransform &t);
0087 
0088     /**
0089      * A helper function for \see map()
0090      */
0091     KisOptimizedBrushOutline mapped(const QTransform &t) const;
0092 
0093     /**
0094      * Begins iteration over the polygons contained in the
0095      * brush outline. KisOptimizedBrushOutline will never return
0096      * a constructed QVector of the polygons, because it may
0097      * require too many memory allocations.
0098      *
0099      * One cannot change the internal polygon, because the
0100      * returned polygon is transformed using the transformation
0101      * that is stored separately.
0102      */
0103     const_iterator begin() const;
0104 
0105     /**
0106      * End iterator for iteration over all the embedded polygons
0107      */
0108     const_iterator end() const;
0109 
0110 private:
0111     QVector<QPolygonF> m_subpaths;
0112     QVector<QPolygonF> m_additionalDecorations;
0113     QTransform m_transform;
0114     mutable QRectF m_cachedBoundingRect;
0115 };
0116 
0117 #endif // KISOPTIMIZEDBRUSHOUTLINE_H