Krita Source Code Documentation
Loading...
Searching...
No Matches
KoClipPath.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2011 Jan Hambrecht <jaham@gmx.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "KoClipPath.h"
8#include "KoPathShape.h"
9#include "KoShapeGroup.h"
10
11#include <QTransform>
12#include <QPainterPath>
13#include <QPainter>
14#include <QVarLengthArray>
15#include <QSharedData>
16
17#include <kis_algebra_2d.h>
18
19
20QTransform scaleToPercent(const QSizeF &size)
21{
22 const qreal w = qMax(static_cast<qreal>(1e-5), size.width());
23 const qreal h = qMax(static_cast<qreal>(1e-5), size.height());
24 return QTransform().scale(1.0/w, 1.0/h);
25}
26
27QTransform scaleFromPercent(const QSizeF &size)
28{
29 const qreal w = qMax(static_cast<qreal>(1e-5), size.width());
30 const qreal h = qMax(static_cast<qreal>(1e-5), size.height());
31 return QTransform().scale(w/1.0, h/1.0);
32}
33
34class Q_DECL_HIDDEN KoClipPath::Private : public QSharedData
35{
36public:
38 : QSharedData()
39 {}
40
41 Private(const Private &rhs)
42 : QSharedData()
43 , clipPath(rhs.clipPath)
44 , clipRule(rhs.clipRule)
45 , coordinates(rhs.coordinates)
46 , initialTransformToShape(rhs.initialTransformToShape)
47 , initialShapeSize(rhs.initialShapeSize)
48 {
49 Q_FOREACH (KoShape *shape, rhs.shapes) {
50 KoShape *clonedShape = shape->cloneShape();
51 KIS_ASSERT_RECOVER(clonedShape) { continue; }
52
53 shapes.append(clonedShape);
54 }
55 }
56
58 {
59 qDeleteAll(shapes);
60 shapes.clear();
61 }
62
63 void collectShapePath(QPainterPath *result, const KoShape *shape) {
64 if (const KoPathShape *pathShape = dynamic_cast<const KoPathShape*>(shape)) {
65 // different shapes add up to the final path using Windind Fill rule (acc. to SVG 1.1)
66 QTransform t = pathShape->absoluteTransformation();
67 result->addPath(t.map(pathShape->outline()));
68 } else if (const KoShapeGroup *groupShape = dynamic_cast<const KoShapeGroup*>(shape)) {
69 QList<KoShape*> shapes = groupShape->shapes();
70 std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
71
72 Q_FOREACH (const KoShape *child, shapes) {
73 collectShapePath(result, child);
74 }
75 }
76 }
77
78
80 {
81 QList<KoShape*> clipShapes = this->shapes;
82 if (clipShapes.isEmpty())
83 return;
84
85 clipPath = QPainterPath();
86 clipPath.setFillRule(Qt::WindingFill);
87
88 std::sort(clipShapes.begin(), clipShapes.end(), KoShape::compareShapeZIndex);
89
90 Q_FOREACH (KoShape *path, clipShapes) {
91 if (!path) continue;
92
93 collectShapePath(&clipPath, path);
94 }
95 }
96
98 QPainterPath clipPath;
99 Qt::FillRule clipRule = Qt::WindingFill;
103};
104
106 : d(new Private())
107{
108 d->shapes = clipShapes;
109 d->coordinates = coordinates;
110 d->compileClipPath();
111}
112
116
118 : d(new Private(*rhs.d))
119{
120}
121
123{
124 d = rhs.d;
125 return *this;
126}
127
129{
130 return new KoClipPath(*this);
131}
132
133void KoClipPath::setClipRule(Qt::FillRule clipRule)
134{
135 d->clipRule = clipRule;
136}
137
138Qt::FillRule KoClipPath::clipRule() const
139{
140 return d->clipRule;
141}
142
144{
145 return d->coordinates;
146}
147
148void KoClipPath::applyClipping(KoShape *shape, QPainter &painter)
149{
150 if (shape->clipPath()) {
151 QPainterPath path = shape->clipPath()->path();
152
154 const QRectF shapeLocalBoundingRect = shape->outline().boundingRect();
155 path = KisAlgebra2D::mapToRect(shapeLocalBoundingRect).map(path);
156 }
157
158 if (!path.isEmpty()) {
159 painter.setClipPath(path, Qt::IntersectClip);
160 }
161 }
162}
163
164QPainterPath KoClipPath::path() const
165{
166 return d->clipPath;
167}
168
169QPainterPath KoClipPath::pathForSize(const QSizeF &size) const
170{
171 return scaleFromPercent(size).map(d->clipPath);
172}
173
175{
176 // TODO: deprecate this method!
177
179
180 Q_FOREACH (KoShape *shape, d->shapes) {
181 KoPathShape *pathShape = dynamic_cast<KoPathShape*>(shape);
182 if (pathShape) {
183 shapes << pathShape;
184 }
185 }
186
187 return shapes;
188}
189
191{
192 return d->shapes;
193}
194
195QTransform KoClipPath::clipDataTransformation(KoShape *clippedShape) const
196{
197 if (!clippedShape)
198 return d->initialTransformToShape;
199
200 // the current transformation of the clipped shape
201 QTransform currentShapeTransform = clippedShape->absoluteTransformation();
202
203 // calculate the transformation which represents any resizing of the clipped shape
204 const QSizeF currentShapeSize = clippedShape->outline().boundingRect().size();
205 const qreal sx = currentShapeSize.width() / d->initialShapeSize.width();
206 const qreal sy = currentShapeSize.height() / d->initialShapeSize.height();
207 QTransform scaleTransform = QTransform().scale(sx, sy);
208
209 // 1. transform to initial clipped shape coordinates
210 // 2. apply resizing transformation
211 // 3. convert to current clipped shape document coordinates
212 return d->initialTransformToShape * scaleTransform * currentShapeTransform;
213}
QTransform scaleFromPercent(const QSizeF &size)
QTransform scaleToPercent(const QSizeF &size)
Clip path used to clip shapes.
void setClipRule(Qt::FillRule clipRule)
Sets the clip rule to be used for the clip path.
KoFlake::CoordinateSystem coordinates
QList< KoPathShape * > clipPathShapes() const
Returns the clip path shapes.
QPainterPath path() const
Returns the current clip path with coordinates in percent of the clipped shape size.
QPainterPath clipPath
the compiled clip path in shape coordinates of the clipped shape
void compileClipPath()
QTransform initialTransformToShape
initial transformation to shape coordinates of the clipped shape
QList< KoShape * > clipShapes() const
QSizeF initialShapeSize
initial size of clipped shape
KoClipPath(QList< KoShape * > clipShapes, KoFlake::CoordinateSystem coordinates)
void collectShapePath(QPainterPath *result, const KoShape *shape)
Qt::FillRule clipRule
KoClipPath * clone() const
static void applyClipping(KoShape *clippedShape, QPainter &painter)
Applies the clipping to the given painter.
QTransform clipDataTransformation(KoShape *clippedShape) const
QPainterPath pathForSize(const QSizeF &size) const
Returns the current clip path scaled to match the specified shape size.
QSharedDataPointer< Private > d
Definition KoClipPath.h:77
KoClipPath & operator=(const KoClipPath &)
QList< KoShape * > shapes
Private(const Private &rhs)
The position of a path point within a path shape.
Definition KoPathShape.h:63
virtual QPainterPath outline() const
Definition KoShape.cpp:630
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:434
KoClipPath * clipPath() const
Returns the currently set clip path or 0 if there is no clip path set.
Definition KoShape.cpp:1128
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
virtual KoShape * cloneShape() const
creates a deep copy of the shape or shape's subtree
Definition KoShape.cpp:200
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
QTransform mapToRect(const QRectF &rect)