Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_wrapped_rect.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#ifndef __KIS_WRAPPED_RECT_H
8#define __KIS_WRAPPED_RECT_H
9
10#include <QVector>
11#include <QRect>
12#include <QtMath>
13
14#include "KisWraparoundAxis.h"
15
16struct KisWrappedRect : public QVector<QRect> {
17 static inline int xToWrappedX(int x, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
18 if (wrapAxis == WRAPAROUND_VERTICAL) {
19 return x;
20 }
21 x = (x - wrapRect.x()) % wrapRect.width();
22 if (x < 0) x += wrapRect.width();
23 return x;
24 }
25
26 static inline int yToWrappedY(int y, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
27 if (wrapAxis == WRAPAROUND_HORIZONTAL) {
28 return y;
29 }
30 y = (y - wrapRect.y()) % wrapRect.height();
31 if (y < 0) y += wrapRect.height();
32 return y;
33 }
34
35 static inline QPoint ptToWrappedPt(QPoint pt, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
36 pt.rx() = xToWrappedX(pt.x(), wrapRect, wrapAxis);
37 pt.ry() = yToWrappedY(pt.y(), wrapRect, wrapAxis);
38 return pt;
39 }
40
41 static inline QRect clipToWrapRect(QRect rc, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
42 switch (wrapAxis) {
44 {
45 if (rc.left() < wrapRect.left()) {
46 rc.setLeft(wrapRect.left());
47 }
48 if (rc.right() > wrapRect.right()) {
49 rc.setRight(wrapRect.right());
50 }
51 return rc;
52 }
54 {
55 if (rc.top() < wrapRect.top()) {
56 rc.setTop(wrapRect.top());
57 }
58 if (rc.bottom() > wrapRect.bottom()) {
59 rc.setBottom(wrapRect.bottom());
60 }
61 return rc;
62 }
63 default /*WRAPAROUND_BOTH*/:
64 return rc & wrapRect;
65 }
66 }
67
68 static inline bool wrapRectContains(const QRect &rc, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
69 switch (wrapAxis) {
71 return (rc.left() >= wrapRect.left() && rc.right() <= wrapRect.right());
73 return (rc.top() >= wrapRect.top() && rc.bottom() <= wrapRect.bottom());
74 default /*WRAPAROUND_BOTH*/:
75 return wrapRect.contains(rc);
76 }
77 }
78 static inline bool wrapRectContains(QPoint pt, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
79 switch (wrapAxis) {
81 return (pt.x() >= wrapRect.left() && pt.x() <= wrapRect.right());
83 return (pt.y() >= wrapRect.top() && pt.y() <= wrapRect.bottom());
84 default /*WRAPAROUND_BOTH*/:
85 return wrapRect.contains(pt);
86 }
87 }
88
93 static inline QVector<QPoint> normalizationOriginsForRect(const QRect &rc, const QRect &wrapRect, WrapAroundAxis wrapAxis) {
94 QVector<QPoint> result;
95
96 if (wrapRectContains(rc, wrapRect, wrapAxis)) {
97 result.append(rc.topLeft());
98 }
99 else {
100 int x = xToWrappedX(rc.x(), wrapRect, wrapAxis);
101 int y = yToWrappedY(rc.y(), wrapRect, wrapAxis);
102 int w = wrapAxis != WRAPAROUND_VERTICAL ? qMin(rc.width(), wrapRect.width()) : rc.width();
103 int h = wrapAxis != WRAPAROUND_HORIZONTAL ? qMin(rc.height(), wrapRect.height()) : rc.height();
104
105 // we ensure that the top/left of the rect belongs to the
106 // visible rectangle
107 Q_ASSERT(wrapRectContains(QPoint(x,y), wrapRect, wrapAxis));
108
109 QRect newRect(x, y, w, h);
110
111 if (!clipToWrapRect(newRect, wrapRect, wrapAxis).isEmpty()) {
112 result.append(QPoint(x, y)); // tl
113 }
114
115 if (wrapAxis != WRAPAROUND_VERTICAL &&
116 !clipToWrapRect(newRect.translated(-wrapRect.width(), 0), wrapRect, wrapAxis).isEmpty()) { // tr
117 result.append(QPoint(x - wrapRect.width(), y));
118 }
119
120 if (wrapAxis != WRAPAROUND_HORIZONTAL &&
121 !clipToWrapRect(newRect.translated(0, -wrapRect.height()), wrapRect, wrapAxis).isEmpty()) { // bl
122 result.append(QPoint(x, y - wrapRect.height()));
123 }
124
125 if (wrapAxis == WRAPAROUND_BOTH &&
126 !clipToWrapRect(newRect.translated(-wrapRect.width(), -wrapRect.height()), wrapRect, wrapAxis).isEmpty()) { // br
127 result.append(QPoint(x - wrapRect.width(), y - wrapRect.height()));
128 }
129 }
130
131 return result;
132 }
133
134 static QVector<QRect> multiplyWrappedRect(const QRect &rc,
135 const QRect &wrapRect,
136 const QRect &limitRect,
137 WrapAroundAxis wrapAxis) {
138
139 QVector<QRect> result;
140
141 const int firstCol =
142 wrapAxis != WRAPAROUND_VERTICAL ? qFloor(qreal(limitRect.x() - wrapRect.x()) / wrapRect.width()) : 0;
143 const int firstRow =
144 wrapAxis != WRAPAROUND_HORIZONTAL ? qFloor(qreal(limitRect.y() - wrapRect.y()) / wrapRect.height()) : 0;
145
146 const int lastCol =
147 wrapAxis != WRAPAROUND_VERTICAL ? qFloor(qreal(limitRect.right() - wrapRect.x()) / wrapRect.width()) : 0;
148 const int lastRow =
149 wrapAxis != WRAPAROUND_HORIZONTAL ? qFloor(qreal(limitRect.bottom() - wrapRect.y()) / wrapRect.height()) : 0;
150
151 KisWrappedRect wrappedRect(rc, wrapRect, wrapAxis);
152
153 Q_FOREACH (const QRect &rect, wrappedRect) {
154 if (rect.isEmpty()) continue;
155
156 for (int y = firstRow; y <= lastRow; y++) {
157 for (int x = firstCol; x <= lastCol; x++) {
158 const QPoint offset(x * wrapRect.width(), y * wrapRect.height());
159 const QRect currentRect =
160 rect.translated(offset + wrapRect.topLeft()) & limitRect;
161
162 if (!currentRect.isEmpty()) {
163 result << currentRect;
164 }
165 }
166 }
167 }
168
169 return result;
170 }
171
172public:
173
174 enum {
179 };
180
181 KisWrappedRect(const QRect &rc, const QRect &wrapRect, WrapAroundAxis wrapAxis)
184 {
185 if (wrapRectContains(rc, wrapRect, wrapAxis)) {
186 append(rc);
187 } else {
188 int x = xToWrappedX(rc.x(), wrapRect, wrapAxis);
189 int y = yToWrappedY(rc.y(), wrapRect, wrapAxis);
190 int w = wrapAxis != WRAPAROUND_VERTICAL ? qMin(rc.width(), wrapRect.width()) : rc.width();
191 int h = wrapAxis != WRAPAROUND_HORIZONTAL ? qMin(rc.height(), wrapRect.height()) : rc.height();
192
193 // we ensure that the top/left of the rect belongs to the
194 // visible rectangle
195 Q_ASSERT(wrapRectContains(QPoint(x,y), wrapRect, wrapAxis));
196
197 QRect newRect(x, y, w, h);
198
199 // We add empty QRects here because a "splitRect" is expected to contain exactly 4 rects.
200 // Functions such as KisPaintDeviceWrappedStrategy::readBytes() and
201 // KisWrappedLineIteratorBase() will not work properly (read: crash) otherwise.
202 append(clipToWrapRect(newRect, wrapRect, wrapAxis)); // tl
203 append(wrapAxis != WRAPAROUND_VERTICAL ?
204 clipToWrapRect(newRect.translated(-wrapRect.width(), 0), wrapRect, wrapAxis) : QRect()); // tr
205 append(wrapAxis != WRAPAROUND_HORIZONTAL ?
206 clipToWrapRect(newRect.translated(0, -wrapRect.height()), wrapRect, wrapAxis) : QRect()); // bl
207 append(wrapAxis == WRAPAROUND_BOTH ?
208 clipToWrapRect(newRect.translated(-wrapRect.width(), -wrapRect.height()), wrapRect, wrapAxis) : QRect()); // br
209 }
210 }
211
212 bool isSplit() const {
213 int size = this->size();
214
215 // we can either split or not split only
216 Q_ASSERT(size == 1 || size == 4);
217
218 return size > 1;
219 }
220
221 QRect topLeft() const {
222 return this->at(TOPLEFT);
223 }
224
225 QRect topRight() const {
226 return this->at(TOPRIGHT);
227 }
228
229 QRect bottomLeft() const {
230 return this->at(BOTTOMLEFT);
231 }
232
233 QRect bottomRight() const {
234 return this->at(BOTTOMRIGHT);
235 }
236
237 QRect wrapRect() const {
238 return m_wrapRect;
239 }
240
241 QRect originalRect() const {
242 return m_originalRect;
243 }
244
245private:
248};
249
250#endif /* __KIS_WRAPPED_RECT_H */
WrapAroundAxis
@ WRAPAROUND_HORIZONTAL
@ WRAPAROUND_BOTH
@ WRAPAROUND_VERTICAL
bool isSplit() const
static int yToWrappedY(int y, const QRect &wrapRect, WrapAroundAxis wrapAxis)
static bool wrapRectContains(const QRect &rc, const QRect &wrapRect, WrapAroundAxis wrapAxis)
static QRect clipToWrapRect(QRect rc, const QRect &wrapRect, WrapAroundAxis wrapAxis)
QRect originalRect() const
QRect topLeft() const
static QVector< QPoint > normalizationOriginsForRect(const QRect &rc, const QRect &wrapRect, WrapAroundAxis wrapAxis)
QRect bottomLeft() const
QRect bottomRight() const
static bool wrapRectContains(QPoint pt, const QRect &wrapRect, WrapAroundAxis wrapAxis)
static QPoint ptToWrappedPt(QPoint pt, const QRect &wrapRect, WrapAroundAxis wrapAxis)
KisWrappedRect(const QRect &rc, const QRect &wrapRect, WrapAroundAxis wrapAxis)
QRect topRight() const
QRect wrapRect() const
static QVector< QRect > multiplyWrappedRect(const QRect &rc, const QRect &wrapRect, const QRect &limitRect, WrapAroundAxis wrapAxis)
static int xToWrappedX(int x, const QRect &wrapRect, WrapAroundAxis wrapAxis)