PlotCursor.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright (C) 2015 by Ralf Kaestner *
3  * ralf.kaestner@gmail.com *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the Lesser GNU General Public License as published by*
7  * the Free Software Foundation; either version 3 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * Lesser GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the Lesser GNU General Public License *
16  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17  ******************************************************************************/
18 
19 #include <cmath>
20 #include <limits>
21 
22 #include <QEvent>
23 #include <QMouseEvent>
24 #include <QPainter>
25 #include <QPen>
26 #include <QResizeEvent>
27 
28 #include <qwt/qwt_plot.h>
29 #include <qwt/qwt_plot_canvas.h>
30 #include <qwt/qwt_plot_curve.h>
31 #include <qwt/qwt_scale_widget.h>
32 
35 
37 
38 namespace rqt_multiplot {
39 
40 /*****************************************************************************/
41 /* Constructors and Destructor */
42 /*****************************************************************************/
43 
44 PlotCursor::PlotCursor(QwtPlotCanvas* canvas) :
45  QwtPlotPicker(canvas),
46  trackPoints_(false),
47  mouseControl_(false) {
48  setTrackerMode(QwtPicker::AlwaysOn);
49  setStateMachine(new PlotCursorMachine());
50 
51  setRubberBand(QwtPicker::CrossRubberBand);
52  setRubberBandPen(Qt::DashLine);
53 
54  connect(plot()->axisWidget(xAxis()), SIGNAL(scaleDivChanged()),
55  this, SLOT(plotXAxisScaleDivChanged()));
56  connect(plot()->axisWidget(yAxis()), SIGNAL(scaleDivChanged()),
57  this, SLOT(plotYAxisScaleDivChanged()));
58 }
59 
61 }
62 
63 /*****************************************************************************/
64 /* Accessors */
65 /*****************************************************************************/
66 
67 void PlotCursor::setActive(bool active, const QPointF& position) {
68  if (mouseControl_)
69  return;
70 
71  if (active && !isActive()) {
72  setTrackerMode(QwtPicker::AlwaysOff);
73 
74  begin();
75  append(transform(position));
76 
77  currentPosition_ = position;
78 
79  emit currentPositionChanged(position);
80  }
81  else if (!active && isActive()) {
82  remove();
83  end();
84 
85  setTrackerMode(QwtPicker::AlwaysOn);
86  }
87 }
88 
89 void PlotCursor::setCurrentPosition(const QPointF& position) {
90  if (mouseControl_)
91  return;
92 
93  if (isActive() && (position != currentPosition_)) {
94  currentPosition_ = position;
95 
96  blockSignals(true);
97  move(transform(position));
98  blockSignals(false);
99  }
100 }
101 
102 const QPointF& PlotCursor::getCurrentPosition() const {
103  return currentPosition_;
104 }
105 
106 void PlotCursor::setTrackPoints(bool track) {
107  if (track != trackPoints_) {
108  trackPoints_ = track;
109 
110  if (isActive())
111  updateDisplay();
112  }
113 }
114 
116  return trackPoints_;
117 }
118 
120  return mouseControl_;
121 }
122 
123 QRect PlotCursor::getTextRect(const QPointF& point, const QFont& font) const {
124  QwtText text = trackerTextF(point);
125 
126  if (text.isEmpty())
127  return QRect();
128 
129  QSizeF textSize = text.textSize(font);
130  QRect textRect(0, 0, qCeil(textSize.width()), qCeil(textSize.height()));
131  QPoint position = transform(point);
132 
133  int alignment = Qt::AlignTop | Qt::AlignRight;
134  int margin = 5;
135  int x = position.x();
136  int y = position.y();
137 
138  if (alignment & Qt::AlignLeft)
139  x -= textRect.width() + margin;
140  else if (alignment & Qt::AlignRight)
141  x += margin;
142 
143  if (alignment & Qt::AlignBottom)
144  y += margin;
145  else if (alignment & Qt::AlignTop)
146  y -= textRect.height() + margin;
147 
148  textRect.moveTopLeft(QPoint(x, y));
149 
150  #if QWT_VERSION >= 0x060100
151  int left = qMax(textRect.left(), trackerRect(font).left()+margin);
152  int right = qMin(textRect.right(), trackerRect(font).right()-margin);
153  int top = qMax(textRect.top(), trackerRect(font).top()+margin);
154  int bottom = qMin( textRect.bottom(), trackerRect(font).bottom()-margin);
155  #else
156  int left = qMax(textRect.left(), pickRect().left()+margin);
157  int right = qMin(textRect.right(), pickRect().right()-margin);
158  int top = qMax(textRect.top(), pickRect().top()+margin);
159  int bottom = qMin( textRect.bottom(), pickRect().bottom()-margin);
160  #endif
161 
162  textRect.moveBottomRight(QPoint(right, bottom));
163  textRect.moveTopLeft(QPoint(left, top));
164 
165  return textRect;
166 }
167 
168 QwtText PlotCursor::trackerTextF(const QPointF& point) const {
169  QwtScaleMap xMap = plot()->canvasMap(xAxis());
170  QwtScaleMap yMap = plot()->canvasMap(yAxis());
171 
172  double xPrecision = log10(fabs(xMap.invTransform(1.0)-
173  xMap.invTransform(0.0)));
174  double yPrecision = log10(fabs(yMap.invTransform(1.0)-
175  yMap.invTransform(0.0)));
176 
177  QString x, y;
178 
179  if ((xPrecision < 0.0) && (fabs(point.x()) >= 1.0))
180  x.sprintf("%.*f", (int)ceil(fabs(xPrecision)), point.x());
181  else
182  x.sprintf("%g", point.x());
183 
184  if ((yPrecision < 0.0) && (fabs(point.y()) >= 1.0))
185  y.sprintf("%.*f", (int)ceil(fabs(yPrecision)), point.y());
186  else
187  y.sprintf("%g", point.y());
188 
189  return QwtText(x+", "+y);
190 }
191 
192 /*****************************************************************************/
193 /* Methods */
194 /*****************************************************************************/
195 
196 void PlotCursor::drawRubberBand(QPainter* painter) const {
197  if (dynamic_cast<QWidget*>(painter->device())) {
198  QPen pen = painter->pen();
199  QColor penColor = pen.color();
200 
201  penColor.setAlphaF(0.3);
202  pen.setColor(penColor);
203 
204  painter->setPen(pen);
205  }
206 
207  QwtPlotPicker::drawRubberBand(painter);
208 
209  drawTrackedPoints(painter);
210 }
211 
213  bool active = isActive();
214 
215  QwtPlotPicker::begin();
216 
217  if (!active && isActive())
218  emit activeChanged(true);
219 }
220 
221 void PlotCursor::move(const QPoint& point) {
222  QPointF newPosition = invTransform(point);
223 
224  if (newPosition != currentPosition_) {
225  currentPosition_ = newPosition;
226 
227  updateDisplay();
228 
229  emit currentPositionChanged(newPosition);
230  }
231 
232  QwtPlotPicker::move(point);
233 }
234 
235 bool PlotCursor::end(bool ok) {
236  bool active = isActive();
237 
238  bool result = QwtPlotPicker::end(ok);
239 
240  if (active && !isActive())
241  emit activeChanged(false);
242 
243  return result;
244 }
245 
246 bool PlotCursor::eventFilter(QObject* object, QEvent* event) {
247  if (object == plot()->canvas()) {
248  if (event->type() == QEvent::Enter)
249  mouseControl_ = true;
250  else if (event->type() == QEvent::Leave)
251  mouseControl_ = false;
252  else if (event->type() == QEvent::MouseButtonRelease)
253  updateDisplay();
254  }
255 
256  bool result = QwtPlotPicker::eventFilter(object, event);
257 
258  if (isActive() && object == plot()->canvas()) {
259  if (event->type() == QEvent::Resize)
260  transition(event);
261  }
262 
263  return result;
264 }
265 
268 
269  QwtPlotPicker::updateDisplay();
270 }
271 
273  trackedPoints_.clear();
274 
275  if (!trackPoints_ || !isActive())
276  return;
277 
278  QwtScaleMap map = plot()->canvasMap(xAxis());
279  double maxDistance = fabs(map.invTransform(1.0)-map.invTransform(0.0));
280 
281  for (QwtPlotItemIterator it = plot()->itemList().begin();
282  it != plot()->itemList().end(); ++it) {
283  if ((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) {
284  QwtPlotCurve* curve = (QwtPlotCurve*)(*it);
285  CurveData* data = dynamic_cast<CurveData*>(curve->data());
286 
287  if (data) {
288  QVector<size_t> indexes = data->getPointsInDistance(
289  currentPosition_.x(), maxDistance);
290 
291  if (!indexes.isEmpty()) {
292  TrackedPoint trackedPoint;
293  trackedPoint.color = curve->pen().color();
294 
295  double minDistance = std::numeric_limits<double>::max();
296 
297  for (size_t index = 0; index < indexes.count(); ++index) {
298  QPointF point = data->getPoint(indexes[index]);
299  QPointF vector = currentPosition_-point;
300  double distance = vector.x()*vector.x()+vector.y()*vector.y();
301 
302  if (distance < minDistance) {
303  trackedPoint.position = point;
304  minDistance = distance;
305  }
306  }
307 
308  trackedPoints_.append(trackedPoint);
309  }
310  }
311  }
312  }
313 }
314 
315 void PlotCursor::drawTrackedPoints(QPainter* painter) const {
316  if (!trackPoints_)
317  return;
318 
319  for (size_t index = 0; index < trackedPoints_.count(); ++index) {
320  QPointF position = trackedPoints_[index].position;
321  QPoint point = transform(position);
322 
323  if (dynamic_cast<QWidget*>(painter->device()))
324  painter->setPen(trackedPoints_[index].color);
325 
326  painter->fillRect(point.x()-3, point.y()-3, 6, 6,
327  painter->pen().color());
328 
329  QRect textRect = getTextRect(position, painter->font());
330 
331  if (!textRect.isEmpty()) {
332  if (dynamic_cast<QWidget*>(painter->device())) {
333  QwtText label = trackerTextF(position);
334 
335  if (!label.isEmpty())
336  label.draw(painter, textRect);
337  }
338  else
339  painter->fillRect(textRect, painter->pen().color());
340  }
341  }
342 }
343 
344 /*****************************************************************************/
345 /* Slots */
346 /*****************************************************************************/
347 
349  if (isActive()) {
350  if (mouseControl_) {
351  QPointF newPosition = currentPosition_;
352 
353  newPosition.setX(plot()->canvasMap(xAxis()).invTransform(
354  pickedPoints()[0].x()));
355 
356  if (newPosition != currentPosition_) {
357  currentPosition_ = newPosition;
358 
359  updateDisplay();
360 
361  emit currentPositionChanged(newPosition);
362  }
363  }
364  else {
365  QPoint newPosition = pickedPoints()[0];
366 
367  newPosition.setX(plot()->canvasMap(xAxis()).transform(
368  currentPosition_.x()));
369 
370  blockSignals(true);
371  move(newPosition);
372  blockSignals(false);
373  }
374  }
375 }
376 
378  if (isActive()) {
379  if (mouseControl_) {
380  QPointF newPosition = currentPosition_;
381 
382  newPosition.setY(plot()->canvasMap(yAxis()).invTransform(
383  pickedPoints()[0].y()));
384 
385  if (newPosition != currentPosition_) {
386  currentPosition_ = newPosition;
387 
388  updateDisplay();
389 
390  emit currentPositionChanged(newPosition);
391  }
392  }
393  else {
394  QPoint newPosition = pickedPoints()[0];
395 
396  newPosition.setY(plot()->canvasMap(yAxis()).transform(
397  currentPosition_.y()));
398 
399  blockSignals(true);
400  move(newPosition);
401  blockSignals(false);
402  }
403  }
404 }
405 
406 }
QRect getTextRect(const QPointF &point, const QFont &font) const
Definition: PlotCursor.cpp:123
void drawTrackedPoints(QPainter *painter) const
Definition: PlotCursor.cpp:315
bool arePointsTracked() const
Definition: PlotCursor.cpp:115
virtual QVector< size_t > getPointsInDistance(double x, double maxDistance) const
Definition: CurveData.cpp:46
QwtText trackerTextF(const QPointF &point) const
Definition: PlotCursor.cpp:168
PlotCursor(QwtPlotCanvas *canvas)
Definition: PlotCursor.cpp:44
bool eventFilter(QObject *object, QEvent *event)
Definition: PlotCursor.cpp:246
void move(const QPoint &point)
Definition: PlotCursor.cpp:221
void setActive(bool active, const QPointF &position=QPointF(0.0, 0.0))
Definition: PlotCursor.cpp:67
bool hasMouseControl() const
Definition: PlotCursor.cpp:119
QVector< TrackedPoint > trackedPoints_
Definition: PlotCursor.h:77
virtual QPointF getPoint(size_t index) const =0
void setCurrentPosition(const QPointF &position)
Definition: PlotCursor.cpp:89
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
void currentPositionChanged(const QPointF &position)
void activeChanged(bool active)
void setTrackPoints(bool track)
Definition: PlotCursor.cpp:106
void drawRubberBand(QPainter *painter) const
Definition: PlotCursor.cpp:196
const QPointF & getCurrentPosition() const
Definition: PlotCursor.cpp:102
bool end(bool ok=true)
Definition: PlotCursor.cpp:235


rqt_multiplot
Author(s): Ralf Kaestner
autogenerated on Wed Jul 10 2019 03:49:44