Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <cmath>
00020 #include <limits>
00021
00022 #include <QEvent>
00023 #include <QMouseEvent>
00024 #include <QPainter>
00025 #include <QPen>
00026 #include <QResizeEvent>
00027
00028 #include <qwt/qwt_plot.h>
00029 #include <qwt/qwt_plot_canvas.h>
00030 #include <qwt/qwt_plot_curve.h>
00031 #include <qwt/qwt_scale_widget.h>
00032
00033 #include <rqt_multiplot/CurveData.h>
00034 #include <rqt_multiplot/PlotCursorMachine.h>
00035
00036 #include "rqt_multiplot/PlotCursor.h"
00037
00038 namespace rqt_multiplot {
00039
00040
00041
00042
00043
00044 PlotCursor::PlotCursor(QwtPlotCanvas* canvas) :
00045 QwtPlotPicker(canvas),
00046 trackPoints_(false),
00047 mouseControl_(false) {
00048 setTrackerMode(QwtPicker::AlwaysOn);
00049 setStateMachine(new PlotCursorMachine());
00050
00051 setRubberBand(QwtPicker::CrossRubberBand);
00052 setRubberBandPen(Qt::DashLine);
00053
00054 connect(plot()->axisWidget(xAxis()), SIGNAL(scaleDivChanged()),
00055 this, SLOT(plotXAxisScaleDivChanged()));
00056 connect(plot()->axisWidget(yAxis()), SIGNAL(scaleDivChanged()),
00057 this, SLOT(plotYAxisScaleDivChanged()));
00058 }
00059
00060 PlotCursor::~PlotCursor() {
00061 }
00062
00063
00064
00065
00066
00067 void PlotCursor::setActive(bool active, const QPointF& position) {
00068 if (mouseControl_)
00069 return;
00070
00071 if (active && !isActive()) {
00072 setTrackerMode(QwtPicker::AlwaysOff);
00073
00074 begin();
00075 append(transform(position));
00076
00077 currentPosition_ = position;
00078
00079 emit currentPositionChanged(position);
00080 }
00081 else if (!active && isActive()) {
00082 remove();
00083 end();
00084
00085 setTrackerMode(QwtPicker::AlwaysOn);
00086 }
00087 }
00088
00089 void PlotCursor::setCurrentPosition(const QPointF& position) {
00090 if (mouseControl_)
00091 return;
00092
00093 if (isActive() && (position != currentPosition_)) {
00094 currentPosition_ = position;
00095
00096 blockSignals(true);
00097 move(transform(position));
00098 blockSignals(false);
00099 }
00100 }
00101
00102 const QPointF& PlotCursor::getCurrentPosition() const {
00103 return currentPosition_;
00104 }
00105
00106 void PlotCursor::setTrackPoints(bool track) {
00107 if (track != trackPoints_) {
00108 trackPoints_ = track;
00109
00110 if (isActive())
00111 updateDisplay();
00112 }
00113 }
00114
00115 bool PlotCursor::arePointsTracked() const {
00116 return trackPoints_;
00117 }
00118
00119 bool PlotCursor::hasMouseControl() const {
00120 return mouseControl_;
00121 }
00122
00123 QRect PlotCursor::getTextRect(const QPointF& point, const QFont& font) const {
00124 QwtText text = trackerTextF(point);
00125
00126 if (text.isEmpty())
00127 return QRect();
00128
00129 QSizeF textSize = text.textSize(font);
00130 QRect textRect(0, 0, qCeil(textSize.width()), qCeil(textSize.height()));
00131 QPoint position = transform(point);
00132
00133 int alignment = Qt::AlignTop | Qt::AlignRight;
00134 int margin = 5;
00135 int x = position.x();
00136 int y = position.y();
00137
00138 if (alignment & Qt::AlignLeft)
00139 x -= textRect.width() + margin;
00140 else if (alignment & Qt::AlignRight)
00141 x += margin;
00142
00143 if (alignment & Qt::AlignBottom)
00144 y += margin;
00145 else if (alignment & Qt::AlignTop)
00146 y -= textRect.height() + margin;
00147
00148 textRect.moveTopLeft(QPoint(x, y));
00149
00150 #if QWT_VERSION >= 0x060100
00151 int left = qMax(textRect.left(), trackerRect(font).left()+margin);
00152 int right = qMin(textRect.right(), trackerRect(font).right()-margin);
00153 int top = qMax(textRect.top(), trackerRect(font).top()+margin);
00154 int bottom = qMin( textRect.bottom(), trackerRect(font).bottom()-margin);
00155 #else
00156 int left = qMax(textRect.left(), pickRect().left()+margin);
00157 int right = qMin(textRect.right(), pickRect().right()-margin);
00158 int top = qMax(textRect.top(), pickRect().top()+margin);
00159 int bottom = qMin( textRect.bottom(), pickRect().bottom()-margin);
00160 #endif
00161
00162 textRect.moveBottomRight(QPoint(right, bottom));
00163 textRect.moveTopLeft(QPoint(left, top));
00164
00165 return textRect;
00166 }
00167
00168 QwtText PlotCursor::trackerTextF(const QPointF& point) const {
00169 QwtScaleMap xMap = plot()->canvasMap(xAxis());
00170 QwtScaleMap yMap = plot()->canvasMap(yAxis());
00171
00172 double xPrecision = log10(fabs(xMap.invTransform(1.0)-
00173 xMap.invTransform(0.0)));
00174 double yPrecision = log10(fabs(yMap.invTransform(1.0)-
00175 yMap.invTransform(0.0)));
00176
00177 QString x, y;
00178
00179 if ((xPrecision < 0.0) && (fabs(point.x()) >= 1.0))
00180 x.sprintf("%.*f", (int)ceil(fabs(xPrecision)), point.x());
00181 else
00182 x.sprintf("%g", point.x());
00183
00184 if ((yPrecision < 0.0) && (fabs(point.y()) >= 1.0))
00185 y.sprintf("%.*f", (int)ceil(fabs(yPrecision)), point.y());
00186 else
00187 y.sprintf("%g", point.y());
00188
00189 return QwtText(x+", "+y);
00190 }
00191
00192
00193
00194
00195
00196 void PlotCursor::drawRubberBand(QPainter* painter) const {
00197 if (dynamic_cast<QWidget*>(painter->device())) {
00198 QPen pen = painter->pen();
00199 QColor penColor = pen.color();
00200
00201 penColor.setAlphaF(0.3);
00202 pen.setColor(penColor);
00203
00204 painter->setPen(pen);
00205 }
00206
00207 QwtPlotPicker::drawRubberBand(painter);
00208
00209 drawTrackedPoints(painter);
00210 }
00211
00212 void PlotCursor::begin() {
00213 bool active = isActive();
00214
00215 QwtPlotPicker::begin();
00216
00217 if (!active && isActive())
00218 emit activeChanged(true);
00219 }
00220
00221 void PlotCursor::move(const QPoint& point) {
00222 QPointF newPosition = invTransform(point);
00223
00224 if (newPosition != currentPosition_) {
00225 currentPosition_ = newPosition;
00226
00227 updateDisplay();
00228
00229 emit currentPositionChanged(newPosition);
00230 }
00231
00232 QwtPlotPicker::move(point);
00233 }
00234
00235 bool PlotCursor::end(bool ok) {
00236 bool active = isActive();
00237
00238 bool result = QwtPlotPicker::end(ok);
00239
00240 if (active && !isActive())
00241 emit activeChanged(false);
00242
00243 return result;
00244 }
00245
00246 bool PlotCursor::eventFilter(QObject* object, QEvent* event) {
00247 if (object == plot()->canvas()) {
00248 if (event->type() == QEvent::Enter)
00249 mouseControl_ = true;
00250 else if (event->type() == QEvent::Leave)
00251 mouseControl_ = false;
00252 else if (event->type() == QEvent::MouseButtonRelease)
00253 updateDisplay();
00254 }
00255
00256 bool result = QwtPlotPicker::eventFilter(object, event);
00257
00258 if (isActive() && object == plot()->canvas()) {
00259 if (event->type() == QEvent::Resize)
00260 transition(event);
00261 }
00262
00263 return result;
00264 }
00265
00266 void PlotCursor::updateDisplay() {
00267 updateTrackedPoints();
00268
00269 QwtPlotPicker::updateDisplay();
00270 }
00271
00272 void PlotCursor::updateTrackedPoints() {
00273 trackedPoints_.clear();
00274
00275 if (!trackPoints_ || !isActive())
00276 return;
00277
00278 QwtScaleMap map = plot()->canvasMap(xAxis());
00279 double maxDistance = fabs(map.invTransform(1.0)-map.invTransform(0.0));
00280
00281 for (QwtPlotItemIterator it = plot()->itemList().begin();
00282 it != plot()->itemList().end(); ++it) {
00283 if ((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) {
00284 QwtPlotCurve* curve = (QwtPlotCurve*)(*it);
00285 CurveData* data = dynamic_cast<CurveData*>(curve->data());
00286
00287 if (data) {
00288 QVector<size_t> indexes = data->getPointsInDistance(
00289 currentPosition_.x(), maxDistance);
00290
00291 if (!indexes.isEmpty()) {
00292 TrackedPoint trackedPoint;
00293 trackedPoint.color = curve->pen().color();
00294
00295 double minDistance = std::numeric_limits<double>::max();
00296
00297 for (size_t index = 0; index < indexes.count(); ++index) {
00298 QPointF point = data->getPoint(indexes[index]);
00299 QPointF vector = currentPosition_-point;
00300 double distance = vector.x()*vector.x()+vector.y()*vector.y();
00301
00302 if (distance < minDistance) {
00303 trackedPoint.position = point;
00304 minDistance = distance;
00305 }
00306 }
00307
00308 trackedPoints_.append(trackedPoint);
00309 }
00310 }
00311 }
00312 }
00313 }
00314
00315 void PlotCursor::drawTrackedPoints(QPainter* painter) const {
00316 if (!trackPoints_)
00317 return;
00318
00319 for (size_t index = 0; index < trackedPoints_.count(); ++index) {
00320 QPointF position = trackedPoints_[index].position;
00321 QPoint point = transform(position);
00322
00323 if (dynamic_cast<QWidget*>(painter->device()))
00324 painter->setPen(trackedPoints_[index].color);
00325
00326 painter->fillRect(point.x()-3, point.y()-3, 6, 6,
00327 painter->pen().color());
00328
00329 QRect textRect = getTextRect(position, painter->font());
00330
00331 if (!textRect.isEmpty()) {
00332 if (dynamic_cast<QWidget*>(painter->device())) {
00333 QwtText label = trackerTextF(position);
00334
00335 if (!label.isEmpty())
00336 label.draw(painter, textRect);
00337 }
00338 else
00339 painter->fillRect(textRect, painter->pen().color());
00340 }
00341 }
00342 }
00343
00344
00345
00346
00347
00348 void PlotCursor::plotXAxisScaleDivChanged() {
00349 if (isActive()) {
00350 if (mouseControl_) {
00351 QPointF newPosition = currentPosition_;
00352
00353 newPosition.setX(plot()->canvasMap(xAxis()).invTransform(
00354 pickedPoints()[0].x()));
00355
00356 if (newPosition != currentPosition_) {
00357 currentPosition_ = newPosition;
00358
00359 updateDisplay();
00360
00361 emit currentPositionChanged(newPosition);
00362 }
00363 }
00364 else {
00365 QPoint newPosition = pickedPoints()[0];
00366
00367 newPosition.setX(plot()->canvasMap(xAxis()).transform(
00368 currentPosition_.x()));
00369
00370 blockSignals(true);
00371 move(newPosition);
00372 blockSignals(false);
00373 }
00374 }
00375 }
00376
00377 void PlotCursor::plotYAxisScaleDivChanged() {
00378 if (isActive()) {
00379 if (mouseControl_) {
00380 QPointF newPosition = currentPosition_;
00381
00382 newPosition.setY(plot()->canvasMap(yAxis()).invTransform(
00383 pickedPoints()[0].y()));
00384
00385 if (newPosition != currentPosition_) {
00386 currentPosition_ = newPosition;
00387
00388 updateDisplay();
00389
00390 emit currentPositionChanged(newPosition);
00391 }
00392 }
00393 else {
00394 QPoint newPosition = pickedPoints()[0];
00395
00396 newPosition.setY(plot()->canvasMap(yAxis()).transform(
00397 currentPosition_.y()));
00398
00399 blockSignals(true);
00400 move(newPosition);
00401 blockSignals(false);
00402 }
00403 }
00404 }
00405
00406 }