Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_measure.cc
Go to the documentation of this file.
1/*
2 *
3 * SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "kis_tool_measure.h"
9
10#include <math.h>
11
12#include <QPainter>
13#include <QLayout>
14#include <QWidget>
15#include <QLabel>
16#include <QPainterPath>
17#include <kcombobox.h>
18
19#include <kis_debug.h>
20#include <klocalizedstring.h>
21
22#include "kis_algebra_2d.h"
23#include "kis_image.h"
24#include "kis_cursor.h"
25#include "KoPointerEvent.h"
26#include "KoCanvasBase.h"
27#include <KoViewConverter.h>
28#include "krita_utils.h"
30#include "kis_canvas2.h"
31#include "KisViewManager.h"
33
34#define INNER_RADIUS 50
35
37 : QWidget(parent),
38 m_resolution(image->xRes()),
39 m_unit(KoUnit::Pixel)
40{
41 m_distance = 0.0;
42
43 QGridLayout* optionLayout = new QGridLayout(this);
44 Q_CHECK_PTR(optionLayout);
45 optionLayout->setContentsMargins(0, 0, 0, 0);
46
47 optionLayout->addWidget(new QLabel(i18n("Distance:"), this), 0, 0);
48 optionLayout->addWidget(new QLabel(i18n("Angle:"), this), 1, 0);
49
50 m_distanceLabel = new QLabel(this);
51 m_distanceLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
52 optionLayout->addWidget(m_distanceLabel, 0, 1);
53
54 m_angleLabel = new QLabel(this);
55 m_angleLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
56 optionLayout->addWidget(m_angleLabel, 1, 1);
57
58 KComboBox* unitBox = new KComboBox(this);
60 connect(unitBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUnitChanged(int)));
61 unitBox->setCurrentIndex(m_unit.indexInListForUi(KoUnit::ListAll));
62
63 optionLayout->addWidget(unitBox, 0, 2);
64 optionLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0, 1, 2);
65
66 connect(image, SIGNAL(sigResolutionChanged(double, double)), this, SLOT(slotResolutionChanged(double, double)));
67}
68
74
76{
77 m_angleLabel->setText(i18nc("angle value in degrees", "%1°", KritaUtils::prettyFormatReal(angle)));
78}
79
85
87{
88 m_resolution = xRes;
90}
91
97
98
100 : KisTool(canvas, KisCursor::crossCursor())
101{
102}
103
107QPointF KisToolMeasure::lockedAngle(QPointF pos)
108{
109 const QPointF lineVector = pos - m_startPos;
110 qreal lineAngle = normalizeAngle(std::atan2(lineVector.y(), lineVector.x()));
111
112 const qreal ANGLE_BETWEEN_CONSTRAINED_LINES = (2 * M_PI) / 24;
113
114 const quint32 constrainedLineIndex = static_cast<quint32>((lineAngle / ANGLE_BETWEEN_CONSTRAINED_LINES) + 0.5);
115 const qreal constrainedLineAngle = constrainedLineIndex * ANGLE_BETWEEN_CONSTRAINED_LINES;
116
117 const qreal lineLength = KisAlgebra2D::norm(lineVector);
118
119 const QPointF constrainedLineVector(lineLength * std::cos(constrainedLineAngle), lineLength * std::sin(constrainedLineAngle));
120
121 const QPointF result = m_startPos + constrainedLineVector;
122
123 return result;
124}
125
126void KisToolMeasure::paint(QPainter& gc, const KoViewConverter &converter)
127{
128 QPen old = gc.pen();
129 QPen pen(Qt::SolidLine);
130 gc.setPen(pen);
131
132 QPainterPath elbowPath;
133 elbowPath.moveTo(m_endPos);
134 elbowPath.lineTo(m_startPos);
135
136 QPointF offset = (m_baseLineVec * INNER_RADIUS).toPoint();
137 QPointF diff = m_endPos-m_startPos;
138
139 bool switch_elbow = QPointF::dotProduct(diff, offset) > 0.0;
140 if(switch_elbow) {
141 elbowPath.lineTo(m_startPos + offset);
142 } else {
143 elbowPath.lineTo(m_startPos - offset);
144 }
145
146 if (distance() >= INNER_RADIUS) {
147 QRectF rectangle(m_startPos.x() - INNER_RADIUS, m_startPos.y() - INNER_RADIUS, 2*INNER_RADIUS, 2*INNER_RADIUS);
148
149 double det = diff.x() * m_baseLineVec.y() - diff.y() * m_baseLineVec.x();
150 int startAngle = -atan2(m_baseLineVec.y(), m_baseLineVec.x()) / (2*M_PI) * 360;
151 int spanAngle = switch_elbow ? -angle() : angle();
152
153 if(!switch_elbow) {
154 startAngle+=180;
155 startAngle%=360;
156 }
157
158 if(det > 0) {
159 spanAngle = -spanAngle;
160 }
161
162 elbowPath.arcTo(rectangle, startAngle, spanAngle);
163 }
164
165 // The opengl renderer doesn't take the QPainter's transform, so the path is scaled here
166 qreal sx, sy;
167 converter.zoom(&sx, &sy);
168 QTransform transf;
169 transf.scale(sx / currentImage()->xRes(), sy / currentImage()->yRes());
170 paintToolOutline(&gc, transf.map(elbowPath));
171
172 gc.setPen(old);
173}
175{
176 KisCanvas2 *kisCanvas = qobject_cast<KisCanvas2*>(canvas());
177 QString message = i18nc("%1=distance %2=unit of distance %3=angle in degrees", "%1 %2\n%3°",
180 QString::number(angle(),'f',1));
181 kisCanvas->viewManager()->showFloatingMessage(message, QIcon(), 2000, KisFloatingMessage::High);
182}
184{
186
187 // Erase old temporary lines
189
192 m_baseLineVec = QVector2D(1.0f, 0.0f);
193
194 Q_EMIT sigDistanceChanged(0.0);
195 Q_EMIT sigAngleChanged(0.0);
196}
197
199{
201
202 // Erase old temporary lines
204
205 QPointF pos = convertToPixelCoord(event);
206
207 if (event->modifiers() & Qt::AltModifier) {
208 QPointF trans = pos - m_endPos;
209 m_startPos += trans;
210 m_endPos += trans;
211 } else if(event->modifiers() & Qt::ShiftModifier){
212 m_endPos = lockedAngle(pos);
213 } else {
214 m_endPos = pos;
215 }
216
217 if(!(event->modifiers() & Qt::ControlModifier)) {
218 m_chooseBaseLineVec = false;
219 } else if(!m_chooseBaseLineVec) {
220 m_chooseBaseLineVec = true;
221 m_baseLineVec = QVector2D(m_endPos-m_startPos).normalized();
222 }
223
226 Q_EMIT sigAngleChanged(angle());
228}
229
237
239{
240 if (!currentImage())
241 return nullptr;
243
244 // See https://bugs.kde.org/show_bug.cgi?id=316896
245 QWidget *specialSpacer = new QWidget(m_optionsWidget);
246 specialSpacer->setObjectName("SpecialSpacer");
247 specialSpacer->setFixedSize(0, 0);
248 m_optionsWidget->layout()->addWidget(specialSpacer);
249
250 m_optionsWidget->setObjectName(toolId() + " option widget");
251 connect(this, SIGNAL(sigDistanceChanged(double)), m_optionsWidget, SLOT(slotSetDistance(double)));
252 connect(this, SIGNAL(sigAngleChanged(double)), m_optionsWidget, SLOT(slotSetAngle(double)));
253 m_optionsWidget->setFixedHeight(m_optionsWidget->sizeHint().height());
254 return m_optionsWidget;
255}
256
258{
259 double dot = QVector2D::dotProduct(QVector2D(m_endPos-m_startPos).normalized(), m_baseLineVec);
260 return acos(qAbs(dot)) / (2*M_PI)*360;
261}
262
264{
265 return QVector2D(m_endPos - m_startPos).length();
266}
267
269{
270 QRectF bound;
271 bound.setTopLeft(m_startPos);
272 bound.setBottomRight(m_endPos);
273 bound = bound.united(QRectF(m_startPos.x() - INNER_RADIUS, m_startPos.y() - INNER_RADIUS, 2 * INNER_RADIUS, 2 * INNER_RADIUS));
274 return bound.normalized();
275}
qreal distance(const QPointF &p1, const QPointF &p2)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void updateCanvas(const QRectF &rc) override
KisViewManager * viewManager() const
void slotSetAngle(double angle)
void slotSetDistance(double distance)
KisToolMeasureOptionsWidget(QWidget *parent, KisImageWSP image)
void slotResolutionChanged(double xRes, double yRes)
void continuePrimaryAction(KoPointerEvent *event) override
KisToolMeasure(KoCanvasBase *canvas)
QVector2D m_baseLineVec
void sigAngleChanged(double angle)
void endPrimaryAction(KoPointerEvent *event) override
void showDistanceAngleOnCanvas()
QPointF lockedAngle(QPointF pos)
QWidget * createOptionWidget() override
~KisToolMeasure() override
void paint(QPainter &gc, const KoViewConverter &converter) override
void beginPrimaryAction(KoPointerEvent *event) override
void sigDistanceChanged(double distance)
KisToolMeasureOptionsWidget * m_optionsWidget
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
Qt::KeyboardModifiers modifiers() const
Q_INVOKABLE QString toolId() const
@ ListAll
Definition KoUnit.h:88
static KoUnit fromListForUi(int index, ListOptions listOptions=ListAll, qreal factor=1.0)
Definition KoUnit.cpp:80
QString symbol() const
Get the symbol string of the unit.
Definition KoUnit.cpp:347
static QStringList listOfUnitNameForUi(ListOptions listOptions=ListAll)
Returns the list of unit types for the UI, controlled with the given listOptions.
Definition KoUnit.cpp:69
qreal toUserValue(qreal ptValue, bool rounding=true) const
Definition KoUnit.cpp:186
int indexInListForUi(ListOptions listOptions=ListAll) const
Definition KoUnit.cpp:101
virtual void zoom(qreal *zoomX, qreal *zoomY) const
std::enable_if< std::is_floating_point< T >::value, T >::type normalizeAngle(T a)
Definition kis_global.h:121
#define M_PI
Definition kis_global.h:111
#define CHECK_MODE_SANITY_OR_RETURN(_mode)
Definition kis_tool.h:27
#define INNER_RADIUS
qreal norm(const T &a)
QString KRITAIMAGE_EXPORT prettyFormatReal(qreal value)
QPointF convertToPixelCoord(KoPointerEvent *e)
Definition kis_tool.cc:189
KisImageWSP currentImage()
Definition kis_tool.cc:393
void paintToolOutline(QPainter *painter, const KisOptimizedBrushOutline &path)
Definition kis_tool.cc:589
QRectF convertToPt(const QRectF &rect)
Definition kis_tool.cc:252
@ PAINT_MODE
Definition kis_tool.h:300
@ HOVER_MODE
Definition kis_tool.h:299
virtual void setMode(ToolMode mode)
Definition kis_tool.cc:403
KisCanvas2 * canvas