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>
19
20#include <KoSelection.h>
21#include <QPointF>
22
23#include <math.h>
24#include <QDebug>
25#include <klocalizedstring.h>
26#include "kis_algebra_2d.h"
27
30 , m_start(clicked)
31{
38
39 Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
41 }
42
43 // Even though we aren't currently activated by the corner handles we might as well code like it
44 switch (direction) {
46 m_top = true; m_bottom = false; m_left = false; m_right = false; break;
48 m_top = true; m_bottom = false; m_left = false; m_right = true; break;
50 m_top = false; m_bottom = false; m_left = false; m_right = true; break;
52 m_top = false; m_bottom = true; m_left = false; m_right = true; break;
54 m_top = false; m_bottom = true; m_left = false; m_right = false; break;
56 m_top = false; m_bottom = true; m_left = true; m_right = false; break;
58 m_top = false; m_bottom = false; m_left = true; m_right = false; break;
60 m_top = true; m_bottom = false; m_left = true; m_right = false; break;
61 default:
62 Q_UNREACHABLE();
63 ;// throw exception ? TODO
64 }
65 m_initialSize = selection->size();
66 m_solidPoint = QPointF(m_initialSize.width() / 2, m_initialSize.height() / 2);
67
68 if (m_top) {
69 m_solidPoint += QPointF(0, m_initialSize.height() / 2);
70 } else if (m_bottom) {
71 m_solidPoint -= QPointF(0, m_initialSize.height() / 2);
72 }
73 if (m_left) {
74 m_solidPoint += QPointF(m_initialSize.width() / 2, 0);
75 } else if (m_right) {
76 m_solidPoint -= QPointF(m_initialSize.width() / 2, 0);
77 }
78
79 m_solidPoint = selection->absoluteTransformation().map(selection->outlineRect().topLeft() + m_solidPoint);
80
81 QPointF edge;
82 qreal angle = 0.0;
83 if (m_top) {
85 angle = 180.0;
86 } else if (m_bottom) {
88 angle = 0.0;
89 } else if (m_left) {
91 angle = 90.0;
92 } else if (m_right) {
94 angle = 270.0;
95 }
96 qreal currentAngle = atan2(edge.y(), edge.x()) / M_PI * 180;
97 m_initialSelectionAngle = currentAngle - angle;
98
99 // use cross product of top edge and left edge of selection bounding rect
100 // to determine if the selection is mirrored
101 QPointF top = selection->absolutePosition(KoFlake::TopRight) - selection->absolutePosition(KoFlake::TopLeft);
102 QPointF left = selection->absolutePosition(KoFlake::BottomLeft) - selection->absolutePosition(KoFlake::TopLeft);
103 m_isMirrored = (top.x() * left.y() - top.y() * left.x()) < 0.0;
104}
105
106void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModifiers modifiers)
107{
108 Q_UNUSED(modifiers);
109 QPointF shearVector = point - m_start;
110
111 QTransform m;
112 m.rotate(-m_initialSelectionAngle);
113 shearVector = m.map(shearVector);
114
115 qreal shearX = 0, shearY = 0;
116
117 if (m_top || m_left) {
118 shearVector = - shearVector;
119 }
120 if (m_top || m_bottom) {
121 shearX = m_initialSize.height() > 0 ? shearVector.x() / m_initialSize.height() : 0;
122 }
123 if (m_left || m_right) {
124 shearY = m_initialSize.width() > 0 ? shearVector.y() / m_initialSize.width() : 0;
125 }
126
127 // if selection is mirrored invert the shear values
128 if (m_isMirrored) {
129 shearX *= -1.0;
130 shearY *= -1.0;
131 }
132
133 const qreal maxSaneShear = 1e6;
134 if ((qAbs(shearX) == 0.0 && qAbs(shearY) == 0.0) ||
135 qAbs(shearX) > maxSaneShear ||
136 qAbs(shearY) > maxSaneShear) {
137
138 return;
139 }
140
141 QTransform matrix;
142 matrix.translate(m_solidPoint.x(), m_solidPoint.y());
143 matrix.rotate(m_initialSelectionAngle);
144 matrix.shear(shearX, shearY);
145 matrix.rotate(-m_initialSelectionAngle);
146 matrix.translate(-m_solidPoint.x(), -m_solidPoint.y());
147
148 QTransform applyMatrix = matrix * m_shearMatrix.inverted();
149
150 Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
151 const QRectF oldDirtyRect = shape->boundingRect();
152 shape->applyAbsoluteTransformation(applyMatrix);
153 shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
154 }
155 m_shearMatrix = matrix;
156}
157
158void ShapeShearStrategy::paint(QPainter &painter, const KoViewConverter &converter)
159{
160 Q_UNUSED(painter);
161 Q_UNUSED(converter);
162}
163
165{
166 QList<QTransform> newTransforms;
167 Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
168 newTransforms << shape->transformation();
169 }
170 const bool nothingChanged =
171 std::equal(m_oldTransforms.begin(), m_oldTransforms.end(),
172 newTransforms.begin(),
173 [] (const QTransform &t1, const QTransform &t2) {
174 return KisAlgebra2D::fuzzyMatrixCompare(t1, t2, 1e-6);
175 });
176
178 if (!nothingChanged) {
180 cmd->setText(kundo2_i18n("Shear"));
181 }
182 return cmd;
183}
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
QPointF absolutePosition(KoFlake::AnchorPosition anchor=KoFlake::Center) const
Definition KoShape.cpp:653
void applyAbsoluteTransformation(const QTransform &matrix)
Definition KoShape.cpp:400
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:335
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:424
virtual void updateAbsolute(const QRectF &rect) const
Definition KoShape.cpp:616
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