Krita Source Code Documentation
Loading...
Searching...
No Matches
KisOptimizedBrushOutline.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QPainterPath>
10#include <QTransform>
11#include <kis_algebra_2d.h>
12
16
17KisOptimizedBrushOutline::KisOptimizedBrushOutline(const QPainterPath &path, const std::optional<QRectF> &bounds)
18 : KisOptimizedBrushOutline(path.toSubpathPolygons().toVector(), bounds)
19{
20 // storing in a form of a QVector is much more efficient
21 // than in a QList
22}
23
25 : m_subpaths(subpaths)
26 , m_explicitBounds(bounds)
27{
28}
29
30void KisOptimizedBrushOutline::map(const QTransform &t)
31{
32 m_transform *= t;
33 m_cachedBoundingRect = QRectF();
34}
35
37{
38 KisOptimizedBrushOutline result(*this);
39 result.map(t);
40 return result;
41}
42
47
52
54{
55 if (!m_cachedBoundingRect.isNull()) return m_cachedBoundingRect;
56
64 QRectF result;
65 bool resultInitialized = false;
66
67 if (m_explicitBounds && !m_explicitBounds->isEmpty()) {
68 result = m_transform.mapRect(*m_explicitBounds);
69 resultInitialized = true;
70 }
71
72 for (auto polyIt = m_subpaths.cbegin(); polyIt != m_subpaths.cend(); ++polyIt) {
82 auto it = polyIt->cbegin();
83
84 if (!resultInitialized && it != polyIt->cend()) {
86 resultInitialized = true;
87 ++it;
88 }
89
90 for (; it != polyIt->cend(); ++it) {
92 }
93 }
94
95 for (auto polyIt = m_additionalDecorations.cbegin(); polyIt != m_additionalDecorations.cend(); ++polyIt) {
96 auto it = polyIt->cbegin();
97
98 if (!resultInitialized && it != polyIt->cend()) {
100 resultInitialized = true;
101 ++it;
102 }
103
104 for (; it != polyIt->cend(); ++it) {
106 }
107 }
108
109 m_cachedBoundingRect = result;
110
111 return result;
112}
113
115{
116 return begin() == end();
117}
118
120{
121 QPainterPath path;
122 path.addRect(rc);
123 addPath(path);
124}
125
126void KisOptimizedBrushOutline::addEllipse(const QPointF &center, qreal rx, qreal ry)
127{
128 QPainterPath path;
129 path.addEllipse(center, rx, ry);
130 addPath(path);
131}
132
133void KisOptimizedBrushOutline::addPath(const QPainterPath &path)
134{
136}
137
139{
140 const QTransform invertedTransform = path.m_transform * m_transform.inverted();
141
143 path.m_subpaths.size() +
144 path.m_additionalDecorations.size());
145
146 for (auto it = path.m_subpaths.cbegin(); it != path.m_subpaths.cend(); ++it) {
147 m_additionalDecorations.append(invertedTransform.map(*it));
148 }
149
150 for (auto it = path.m_additionalDecorations.cbegin(); it != path.m_additionalDecorations.cend(); ++it) {
151 m_additionalDecorations.append(invertedTransform.map(*it));
152 }
153
154 m_cachedBoundingRect = QRectF();
155}
156
158{
159 map(QTransform::fromTranslate(tx, ty));
160}
161
162void KisOptimizedBrushOutline::translate(const QPointF &offset)
163{
164 translate(offset.x(), offset.y());
165}
166
168{
169 int index = m_index;
170
171 if (index < m_outline->m_subpaths.size()) {
172 return m_outline->m_transform.map(m_outline->m_subpaths.at(index));
173 }
174
175 index -= m_outline->m_subpaths.size();
176 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(index >= 0, QPolygonF());
177 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(index < m_outline->m_additionalDecorations.size(), QPolygonF());
178
180}
void translate(qreal tx, qreal ty)
std::optional< QRectF > m_explicitBounds
void addPath(const QPainterPath &path)
QVector< QPolygonF > m_additionalDecorations
void map(const QTransform &t)
KisOptimizedBrushOutline mapped(const QTransform &t) const
void addEllipse(const QPointF &center, qreal rx, qreal ry)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define bounds(x, a, b)
void resetEmptyRectangle(const QPoint &pt, QRect *rc)
void accumulateBoundsNonEmpty(const Point &pt, Rect *bounds)