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

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #ifndef KISREGION_H
0007 #define KISREGION_H
0008 
0009 #include "kritaglobal_export.h"
0010 #include <QVector>
0011 #include <QRect>
0012 #include <boost/operators.hpp>
0013 
0014 class QRegion;
0015 
0016 /**
0017  * An more efficient (and more limited) replacement for QRegion.
0018  *
0019  * Its main purpose it to be able to merge a huge set of rectangles
0020  * into a smaller set of bigger rectangles, the same thing that QRegion
0021  * is supposed to do. The main difference (and limitation) is: all the
0022  * input rects must be non-intersecting. This requirement is perfectly
0023  * fine for Krita's tiles, which do never intersect.
0024  */
0025 class KRITAGLOBAL_EXPORT KisRegion :
0026         public boost::equality_comparable<KisRegion>,
0027         public boost::andable<KisRegion, QRect>
0028 {
0029 public:
0030     /**
0031      * @brief merge a set of rectangles into a smaller set of bigger rectangles
0032      *
0033      * The algorithm does two passes over the rectangles. First it tries to
0034      * merge all the rectangles horizontally, then vertically. The merge happens
0035      * in-place, that is, all the merged elements will be moved to the front
0036      * of the original range.
0037      *
0038      * The final range is defined by [beginIt, retvalIt)
0039      *
0040      * @param beginIt iterator to the beginning of the source range
0041      * @param endIt iterator to the end of the source range
0042      * @return iteration pointing past the last element of the merged range
0043      */
0044     static QVector<QRect>::iterator mergeSparseRects(QVector<QRect>::iterator beginIt, QVector<QRect>::iterator endIt);
0045 
0046 
0047     /**
0048      * Simplifies \p rects in a way that they don't overlap anymore. The actual
0049      * resulting area may be larger than original \p rects, but not more than
0050      * \p gridSize in any dimension.
0051      */
0052     static void approximateOverlappingRects(QVector<QRect> &rects, int gridSize);
0053 
0054     static void makeGridLikeRectsUnique(QVector<QRect> &rects);
0055 
0056 public:
0057     KisRegion() = default;
0058     KisRegion(const KisRegion &rhs) = default;
0059     KisRegion(const QRect &rect);
0060     KisRegion(std::initializer_list<QRect> rects);
0061 
0062     /**
0063      * @brief creates a region from a set of non-intersecting rectangles
0064      * @param rects rectangles that should be merged. Rectangles must not intersect.
0065      */
0066     KisRegion(const QVector<QRect> &rects);
0067     KisRegion(QVector<QRect> &&rects);
0068 
0069     KisRegion& operator=(const KisRegion &rhs);
0070     friend KRITAGLOBAL_EXPORT bool operator==(const KisRegion &lhs, const KisRegion &rhs);
0071 
0072     KisRegion& operator&=(const QRect &rect);
0073 
0074     QRect boundingRect() const;
0075     QVector<QRect> rects() const;
0076     int rectCount() const;
0077     bool isEmpty() const;
0078 
0079     QRegion toQRegion() const;
0080 
0081     void translate(int dx, int dy);
0082     KisRegion translated(int x, int y) const;
0083 
0084     static KisRegion fromQRegion(const QRegion &region);
0085 
0086     /**
0087      * Approximates a KisRegion from \p rects, which may overlap. The resulting
0088      * KisRegion may be larger than the original set of rects, but it is guaranteed
0089      * to cover it completely.
0090      */
0091     static KisRegion fromOverlappingRects(const QVector<QRect> &rects, int gridSize);
0092 
0093 private:
0094     void mergeAllRects();
0095 
0096 private:
0097     QVector<QRect> m_rects;
0098 };
0099 
0100 KRITAGLOBAL_EXPORT bool operator==(const KisRegion &lhs, const KisRegion &rhs);
0101 
0102 
0103 #endif // KISREGION_H