Krita Source Code Documentation
Loading...
Searching...
No Matches
ShapeShearStrategy.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2006-2007 Thomas Zander <zander@kde.org>
3 * SPDX-FileCopyrightText: 2006 C. Boemann <cbo@boemann.dk>
4 * SPDX-FileCopyrightText: 2008 Jan Hambrecht <jaham@gmx.net>
5 *
6 * SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
10#include "SelectionDecorator.h"
11
12#include <KoToolBase.h>
13#include <KoCanvasBase.h>
14#include <KoPointerEvent.h>
15#include <KoShapeManager.h>
20
21#include <KoSelection.h>
22#include <QPointF>
23
24#include <math.h>
25#include <QDebug>
26#include <klocalizedstring.h>
27#include "kis_algebra_2d.h"
28
31 , m_start(clicked)
32{
39
40 Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
42 }
43
44 // Even though we aren't currently activated by the corner handles we might as well code like it
45 switch (direction) {
47 m_top = true; m_bottom = false; m_left = false; m_right = false; break;
49 m_top = true; m_bottom = false; m_left = false; m_right = true; break;
51 m_top = false; m_bottom = false; m_left = false; m_right = true; break;
53 m_top = false; m_bottom = true; m_left = false; m_right = true; break;
55 m_top = false; m_bottom = true; m_left = false; m_right = false; break;
57 m_top = false; m_bottom = true; m_left = true; m_right = false; break;
59 m_top = false; m_bottom = false; m_left = true; m_right = false; break;
61 m_top = true; m_bottom = false; m_left = true; m_right = false; break;
62 default:
63 Q_UNREACHABLE();
64 ;// throw exception ? TODO
65 }
66 m_initialSize = selection->size();
67 m_solidPoint = QPointF(m_initialSize.width() / 2, m_initialSize.height() / 2);
68
69 if (m_top) {
70 m_solidPoint += QPointF(0, m_initialSize.height() / 2);
71 } else if (m_bottom) {
72 m_solidPoint -= QPointF(0, m_initialSize.height() / 2);
73 }
74 if (m_left) {
75 m_solidPoint += QPointF(m_initialSize.width() / 2, 0);
76 } else if (m_right) {
77 m_solidPoint -= QPointF(m_initialSize.width() / 2, 0);
78 }
79
80 m_solidPoint = selection->absoluteTransformation().map(selection->outlineRect().topLeft() + m_solidPoint);
81
82 QPointF edge;
83 qreal angle = 0.0;
84 if (m_top) {
86 angle = 180.0;
87 } else if (m_bottom) {
89 angle = 0.0;
90 } else if (m_left) {
92 angle = 90.0;
93 } else if (m_right) {
95 angle = 270.0;
96 }
97 qreal currentAngle = atan2(edge.y(), edge.x()) / M_PI * 180;
98 m_initialSelectionAngle = currentAngle - angle;
99
100 // use cross product of top edge and left edge of selection bounding rect
101 // to determine if the selection is mirrored
102 QPointF top = selection->absolutePosition(KoFlake::TopRight) - selection->absolutePosition(KoFlake::TopLeft);
103 QPointF left = selection->absolutePosition(KoFlake::BottomLeft) - selection->absolutePosition(KoFlake::TopLeft);
104 m_isMirrored = (top.x() * left.y() - top.y() * left.x()) < 0.0;
105}
106
107void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModifiers modifiers)
108{
109 Q_UNUSED(modifiers);
110 QPointF shearVector = point - m_start;
111
112 QTransform m;
113 m.rotate(-m_initialSelectionAngle);
114 shearVector = m.map(shearVector);
115
116 qreal shearX = 0, shearY = 0;
117
118 if (m_top || m_left) {
119 shearVector = - shearVector;
120 }
121 if (m_top || m_bottom) {
122 shearX = m_initialSize.height() > 0 ? shearVector.x() / m_initialSize.height() : 0;
123 }
124 if (m_left || m_right) {
125 shearY = m_initialSize.width() > 0 ? shearVector.y() / m_initialSize.width() : 0;
126 }
127
128 // if selection is mirrored invert the shear values
129 if (m_isMirrored) {
130 shearX *= -1.0;
131 shearY *= -1.0;
132 }
133
134 const qreal maxSaneShear = 1e6;
135 if ((qAbs(shearX) == 0.0 && qAbs(shearY) == 0.0) ||
136 qAbs(shearX) > maxSaneShear ||
137 qAbs(shearY) > maxSaneShear) {
138
139 return;
140 }
141
142 QTransform matrix;
143 matrix.translate(m_solidPoint.x(), m_solidPoint.y());
144 matrix.rotate(m_initialSelectionAngle);
145 matrix.shear(shearX, shearY);
146 matrix.rotate(-m_initialSelectionAngle);
147 matrix.translate(-m_solidPoint.x(), -m_solidPoint.y());
148
149 QTransform applyMatrix = matrix * m_shearMatrix.inverted();
150
152
153 Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
154 shape->applyAbsoluteTransformation(applyMatrix);
155 }
156
158
159 m_shearMatrix = matrix;
160}
161
162void ShapeShearStrategy::paint(QPainter &painter, const KoViewConverter &converter)
163{
164 Q_UNUSED(painter);
165 Q_UNUSED(converter);
166}
167
169{
170 QList<QTransform> newTransforms;
171 Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
172 newTransforms << shape->transformation();
173 }
174 const bool nothingChanged =
175 std::equal(m_oldTransforms.begin(), m_oldTransforms.end(),
176 newTransforms.begin(),
177 [] (const QTransform &t1, const QTransform &t2) {
178 return KisAlgebra2D::fuzzyMatrixCompare(t1, t2, 1e-6);
179 });
180
182 if (!nothingChanged) {
184 cmd->setText(kundo2_i18n("Shear"));
185 }
186 return cmd;
187}
void setText(const KUndo2MagicString &text)
QRectF outlineRect() const override
QSizeF size() const override
Get the size of the shape in pt.
const QList< KoShape * > selectedEditableShapes() const
static void bulkShapesUpdate(const UpdatesList &updates)
QPointF absolutePosition(KoFlake::AnchorPosition anchor=KoFlake::Center) const
Definition KoShape.cpp:573
void applyAbsoluteTransformation(const QTransform &matrix)
Definition KoShape.cpp:353
QTransform absoluteTransformation() const
Definition KoShape.cpp:335
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:383
ShapeShearStrategy(KoToolBase *tool, KoSelection *selection, const QPointF &clicked, KoFlake::SelectionHandle direction)
QList< KoShape * > m_transformedShapesAndSelection
KUndo2Command * createCommand() override
void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override
QList< QTransform > m_oldTransforms
void paint(QPainter &painter, const KoViewConverter &converter) override
#define M_PI
Definition kis_global.h:111
KUndo2MagicString kundo2_i18n(const char *text)
@ BottomRight
Definition KoFlake.h:94
@ TopRight
Definition KoFlake.h:88
@ TopLeft
Definition KoFlake.h:86
@ BottomLeft
Definition KoFlake.h:92
SelectionHandle
Enum determining which handle is meant, used in KoInteractionTool.
Definition KoFlake.h:55
@ BottomRightHandle
The handle that is at the bottom right of a selection.
Definition KoFlake.h:59
@ BottomLeftHandle
The handle that is at the bottom left of a selection.
Definition KoFlake.h:61
@ RightMiddleHandle
The handle that is at the right - center of a selection.
Definition KoFlake.h:58
@ TopRightHandle
The handle that is at the top - right of a selection.
Definition KoFlake.h:57
@ TopLeftHandle
The handle that is at the top left of a selection.
Definition KoFlake.h:63
@ LeftMiddleHandle
The handle that is at the left center of a selection.
Definition KoFlake.h:62
@ TopMiddleHandle
The handle that is at the top - center of a selection.
Definition KoFlake.h:56
@ BottomMiddleHandle
The handle that is at the bottom center of a selection.
Definition KoFlake.h:60