628 lines
17 KiB
C++
Executable File
628 lines
17 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* Widget that visualizes the topography of a bunch of points along a rubberband
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Malte Schroeder, NLSE, 2018-03-07
|
|
*/
|
|
|
|
#include "lts_height_plot_widget.h"
|
|
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QPen>
|
|
#include <QTransform>
|
|
#include <QMouseEvent>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
static inline double getLength(const QPointF &p1, const QPointF &p2)
|
|
{
|
|
const double x = p1.x() - p2.x();
|
|
const double y = p1.y() - p2.y();
|
|
return sqrt(x * x + y * y);
|
|
}
|
|
|
|
class LtsHeightPlotWidget::Private
|
|
{
|
|
public:
|
|
Private()
|
|
: m_length(0)
|
|
, m_minElevation(0)
|
|
, m_maxElevation(0)
|
|
, m_nullX(0)
|
|
, m_nullY(0)
|
|
, m_scaleX(0)
|
|
, m_scaleY(0)
|
|
, m_fillBrush(Qt::gray)
|
|
, m_axisPen(Qt::black)
|
|
, m_mousePosPen(Qt::blue)
|
|
, m_markerPen(Qt::magenta)
|
|
, iPositionHint(1)
|
|
{
|
|
m_axisPen.setWidth(1);
|
|
m_viewLinePen.setWidth(1);
|
|
m_textFont.setPixelSize(10);
|
|
m_markerPen.setWidth(2);
|
|
m_markerPen.setCapStyle(Qt::RoundCap);
|
|
m_mousePosPen.setStyle(Qt::DashDotDotLine);
|
|
m_viewLinePen.setStyle(Qt::DashLine);
|
|
}
|
|
void clearPixmap();
|
|
|
|
double getDataHeight(double pos) const;
|
|
QPointF getDataPos(double pos) const;
|
|
int findDataPointIdx(const QPointF &point) const;
|
|
void clear();
|
|
void recalcData();
|
|
void setData(const QVector<QPair<QPointF, double> > &data);
|
|
void setMarks(const QVector<QPointF> &data);
|
|
void resize(const QSize &newSize);
|
|
void repaint();
|
|
void paintLines(QPainter &p) const;
|
|
|
|
QVector< QPair< QPointF, double > > m_data;
|
|
QVector< QPointF > m_marks;
|
|
QVector< QPair< double, double > > m_heightList; // Laenge, Hoehe
|
|
|
|
double m_length;
|
|
double m_minElevation;
|
|
double m_maxElevation;
|
|
double m_nullX;
|
|
double m_nullY;
|
|
double m_scaleX;
|
|
double m_scaleY;
|
|
QPainterPath m_drawPoints; // PainterPath der Daten, unskaliert
|
|
QBrush m_fillBrush;
|
|
QPen m_axisPen;
|
|
QPen m_viewLinePen;
|
|
QPen m_mousePosPen;
|
|
QPen m_markerPen;
|
|
QFont m_textFont;
|
|
QPointF m_mousePos;
|
|
QPointF m_mouseLeftClickPos;
|
|
|
|
QSize m_curSize; // aktuelle Groesse des Widgets
|
|
QTransform m_trans1; // nur Verschiebung des Koordinatensystem
|
|
QTransform m_trans2; // Translation Pixel <-> Daten
|
|
QTransform m_transInverted; // m_trans1.inverted() * m_trans2.inverted()
|
|
QTransform m_transCombined; // m_trans2 * m_trans1
|
|
|
|
QPixmap m_pixmap;
|
|
|
|
mutable int iPositionHint;
|
|
};
|
|
|
|
double LtsHeightPlotWidget::Private::getDataHeight(double pos) const
|
|
{
|
|
if (m_heightList.count() <= 1)
|
|
return 0;
|
|
// boundary checks
|
|
if (pos <= 0.)
|
|
return m_heightList[0].second;
|
|
if (pos >= m_heightList[m_heightList.count() - 1].first)
|
|
return m_heightList[m_heightList.count() - 1].second;
|
|
|
|
if (iPositionHint >= m_heightList.size())
|
|
iPositionHint = 1;
|
|
if (pos <= m_heightList[iPositionHint].first)
|
|
{
|
|
while (iPositionHint > 1 && pos <= m_heightList[iPositionHint - 1].first)
|
|
--iPositionHint;
|
|
}
|
|
else
|
|
{
|
|
while (iPositionHint < m_heightList.count() - 1 && pos > m_heightList[iPositionHint].first)
|
|
++iPositionHint;
|
|
}
|
|
const int iFound = iPositionHint;
|
|
// y = m*x + n
|
|
const double x = m_heightList[iFound].first - m_heightList[iFound - 1].first;
|
|
const double y = m_heightList[iFound].second - m_heightList[iFound - 1].second;
|
|
const double m = y / x;
|
|
const double n = m_heightList[iFound].second - m * m_heightList[iFound].first;
|
|
return m * pos + n;
|
|
}
|
|
|
|
QPointF LtsHeightPlotWidget::Private::getDataPos(double pos) const
|
|
{
|
|
if (m_heightList.count() <= 1)
|
|
return QPointF();
|
|
// boundary checks
|
|
if (pos <= 0.)
|
|
return m_data[0].first;
|
|
if (pos >= m_heightList[m_heightList.count() - 1].first)
|
|
return m_data[m_heightList.count() - 1].first;
|
|
|
|
if (pos <= m_heightList[iPositionHint].first)
|
|
{
|
|
while (iPositionHint > 1 && pos <= m_heightList[iPositionHint - 1].first)
|
|
--iPositionHint;
|
|
}
|
|
else
|
|
{
|
|
while (iPositionHint < m_heightList.count() - 1 && pos > m_heightList[iPositionHint].first)
|
|
++iPositionHint;
|
|
}
|
|
const int iFound = iPositionHint;
|
|
// pos = pos1 + pos1 * prozent(p1,p2)
|
|
const double diff = m_heightList[iFound].first - m_heightList[iFound - 1].first;
|
|
double percentile = (pos - m_heightList[iFound - 1].first) / diff;
|
|
const QPointF &p1 = m_data[iFound - 1].first;
|
|
const QPointF p2 = m_data[iFound].first - m_data[iFound - 1].first;
|
|
return QPointF(p1.x() + p2.x() * percentile, p1.y() + p2.y() * percentile);
|
|
}
|
|
|
|
int LtsHeightPlotWidget::Private::findDataPointIdx(const QPointF &point) const
|
|
{
|
|
for (int i = 0; i < m_heightList.count() - 1; ++i)
|
|
{
|
|
// y = m*x + n
|
|
const double x = m_data[i + 1].first.x() - m_data[i].first.x();
|
|
const double y = m_data[i + 1].first.y() - m_data[i].first.y();
|
|
const double m = y / x;
|
|
const double n = m_data[i].first.y() - m * m_data[i].first.x();
|
|
|
|
// Punkt testen ob er auf der Linie liegt
|
|
const double yRes = m * point.x() + n;
|
|
if (fabs(yRes - point.y()) < 1.)
|
|
{
|
|
// und schauen ob er nicht hinter dem zweiten Punkt liegt
|
|
const double len = getLength(m_data[ i ].first, point);
|
|
if (len <= m_heightList[i].first)
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::clear()
|
|
{
|
|
m_data.clear();
|
|
m_marks.clear();
|
|
m_length = 0;
|
|
m_minElevation = 0;
|
|
m_maxElevation = 0;
|
|
m_scaleX = 0;
|
|
m_scaleY = 0;
|
|
m_drawPoints = QPainterPath();
|
|
m_heightList.clear();
|
|
m_curSize = QSize();
|
|
|
|
iPositionHint = 1;
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::clearPixmap()
|
|
{
|
|
m_pixmap = QPixmap();
|
|
}
|
|
|
|
inline double log5(double x)
|
|
{
|
|
return log10(x) / log10(5.);
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::recalcData()
|
|
{
|
|
m_heightList.clear();
|
|
m_drawPoints = QPainterPath();
|
|
|
|
if (m_data.isEmpty())
|
|
{
|
|
clear();
|
|
return;
|
|
}
|
|
|
|
double length = 0;
|
|
double minElevation = m_data.at(0).second;
|
|
double maxElevation = minElevation;
|
|
|
|
for (int i = 1; i < m_data.count(); ++i)
|
|
{
|
|
length += getLength(m_data.at(i - 1).first, m_data.at(i).first);
|
|
minElevation = std::min(minElevation, m_data.at(i).second);
|
|
maxElevation = std::max(maxElevation, m_data.at(i).second);
|
|
}
|
|
// some sanity checks:
|
|
if (minElevation < -10000.0) minElevation = -10000.0;
|
|
if (maxElevation < -10000.0) maxElevation = -10000.0;
|
|
|
|
if (minElevation > 10000.0) minElevation = 10000.0;
|
|
if (maxElevation > 10000.0) maxElevation = 10000.0;
|
|
|
|
if (qFuzzyCompare(minElevation, maxElevation))
|
|
{
|
|
minElevation -= 1.0;
|
|
maxElevation += 1.0;
|
|
}
|
|
|
|
// Laenge auf 5^(n-1) m runden
|
|
double n2 = pow(5, floor(log5(fabs(minElevation))) - 1);
|
|
if (qFuzzyIsNull(n2))
|
|
n2 = 0.1; // avoid division by zero
|
|
|
|
m_minElevation = lrint(floor(minElevation / n2) * n2);
|
|
m_maxElevation = lrint(ceil(maxElevation / n2) * n2);
|
|
m_scaleY = pow(10, floor(log10(m_maxElevation - m_minElevation)) - 1);
|
|
if (m_scaleY < 0.1)
|
|
m_scaleY = 0.1;
|
|
m_nullY = m_minElevation;
|
|
if (m_minElevation < 0 && m_maxElevation > 0)
|
|
m_nullY = 0;
|
|
|
|
// Laenge auf 10^n / 2 m runden
|
|
const double n = pow(10, floor(log10(length))) / 2;
|
|
m_length = lrint(ceil(length / n) * n);
|
|
m_scaleX = pow(10, floor(log10(length)) - 1);
|
|
if (m_scaleX < 0.1)
|
|
m_scaleX = 0.1;
|
|
m_nullX = 0;
|
|
|
|
double len = 0;
|
|
m_drawPoints.moveTo(len, m_data.at(0).second);
|
|
m_heightList.append(QPair<double, double>(len, m_data.at(0).second));
|
|
for (int i = 1; i < m_data.count(); ++i)
|
|
{
|
|
len += getLength(m_data.at(i - 1).first, m_data.at(i).first);
|
|
m_drawPoints.lineTo(len, m_data.at(i).second);
|
|
|
|
m_heightList.append(QPair<double, double>(len, m_data.at(i).second));
|
|
//fprintf(stderr, "point at len %f\n", len);
|
|
}
|
|
m_drawPoints.lineTo(len, m_minElevation);
|
|
m_drawPoints.lineTo(0, m_minElevation);
|
|
m_drawPoints.setFillRule(Qt::WindingFill);
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::setData(const QVector< QPair< QPointF, double > > &data)
|
|
{
|
|
if (data.isEmpty())
|
|
{
|
|
clear();
|
|
return;
|
|
}
|
|
QSize tmp = m_curSize;
|
|
clear();
|
|
|
|
m_data = data;
|
|
|
|
recalcData();
|
|
resize(tmp);
|
|
}
|
|
|
|
|
|
void LtsHeightPlotWidget::Private::setMarks(const QVector< QPointF > &data)
|
|
{
|
|
m_marks = data;
|
|
|
|
recalcData();
|
|
repaint();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::resize(const QSize &newSize)
|
|
{
|
|
if (newSize == m_curSize)
|
|
return;
|
|
|
|
m_curSize = newSize;
|
|
|
|
const int border = 25;
|
|
const double width = m_curSize.width();
|
|
const double height = m_curSize.height();
|
|
|
|
const double minY = m_minElevation - m_scaleY;
|
|
const double maxY = m_maxElevation + m_scaleY;
|
|
const double wertebereichY = maxY - minY;
|
|
|
|
const double minX = 0 - m_scaleX;
|
|
const double maxX = m_length + m_scaleX;
|
|
const double wertebereichX = maxX - minX;
|
|
|
|
m_trans1.reset();
|
|
m_trans2.reset();
|
|
|
|
// 10 Pixel nach rechts und y = 0 ist unten anstatt oben
|
|
m_trans1.translate(10, height);
|
|
// + und - y tauschen - damit im ersten Quadrant x und y positiv sind
|
|
m_trans1.scale(1, -1);
|
|
// und noch etwas vom Rand weg
|
|
m_trans1.translate(border, border);
|
|
// und wieder zurueck
|
|
m_trans1.scale(1, -1);
|
|
|
|
// die aktuelle Breite und Hoehe relativ zu der Breite und Hoehe der Daten
|
|
m_trans2.scale((width - 2 * border) / (wertebereichX),
|
|
(height - 2 * border) / (wertebereichY));
|
|
// m_minElevation ist unser '0-Wert', minY demnach der kleinste y-Wert
|
|
m_trans2.translate(0, minY);
|
|
// + und - y tauschen - damit im ersten Quadrant x und y positiv sind
|
|
m_trans2.scale(1, -1);
|
|
|
|
m_transInverted = m_trans1.inverted() * m_trans2.inverted();
|
|
m_transCombined = m_trans2 * m_trans1;
|
|
|
|
repaint();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::repaint()
|
|
{
|
|
if (!m_curSize.isValid())
|
|
return;
|
|
if (!m_heightList.count())
|
|
return;
|
|
|
|
QImage img(m_curSize, QImage::Format_ARGB32);
|
|
img.fill(Qt::transparent);
|
|
QPainter p(&img);
|
|
const QPainter::RenderHints hints = QPainter::HighQualityAntialiasing |
|
|
QPainter::SmoothPixmapTransform |
|
|
QPainter::TextAntialiasing |
|
|
QPainter::Antialiasing;
|
|
p.setRenderHints(hints);
|
|
p.setTransform(m_trans1);
|
|
|
|
// Daten zeichnen
|
|
p.setPen(QPen(m_fillBrush, 0.1));
|
|
p.setBrush(m_fillBrush);
|
|
p.drawPath(m_trans2.map(m_drawPoints));
|
|
p.setRenderHint(QPainter::Antialiasing, false);
|
|
|
|
// Marker zeichnen
|
|
p.setPen(m_markerPen);
|
|
for (int i = 0; i < m_marks.count(); ++i)
|
|
{
|
|
int posIdx = findDataPointIdx(m_marks.at(i));
|
|
if (posIdx < 0)
|
|
continue;
|
|
double len = getLength(m_data.at(posIdx).first, m_marks.at(i));
|
|
len += m_heightList.at(posIdx).first;
|
|
const double height = getDataHeight(len);
|
|
const QLineF l(len, m_minElevation, len, height);
|
|
//fprintf(stderr, "marker at len %f\n", len);
|
|
|
|
p.drawLine(m_trans2.map(l));
|
|
}
|
|
|
|
// Koordinatensystem + Beschriftung
|
|
p.setPen(m_axisPen);
|
|
p.setFont(m_textFont);
|
|
|
|
// Y-Achse
|
|
p.drawLine(m_trans2.map(QPointF(m_nullX, m_minElevation - m_scaleY)),
|
|
m_trans2.map(QPointF(m_nullX, m_maxElevation + m_scaleY)));
|
|
|
|
// kleine Striche
|
|
for (double i = m_minElevation; i <= m_maxElevation; i += m_scaleY)
|
|
{
|
|
const qreal y = m_trans2.map(QPointF(0, i)).y();
|
|
p.drawLine(QLineF(-2, y, 2, y));
|
|
}
|
|
|
|
// grosse Striche
|
|
for (double i = m_minElevation; i <= m_maxElevation; i += m_scaleY * 5)
|
|
{
|
|
const qreal y = m_trans2.map(QPointF(0, i)).y();
|
|
p.drawLine(QLineF(-4, y, 4, y));
|
|
}
|
|
|
|
QFontMetricsF fm(m_textFont);
|
|
for (double i = m_minElevation; i <= m_maxElevation; i += m_scaleY * 5)
|
|
{
|
|
if (qFuzzyCompare(i, m_nullY))
|
|
continue;
|
|
const qreal y = m_trans2.map(QPointF(m_nullX, i)).y();
|
|
const QPointF p1(-20, y);
|
|
const QString str = QString::number(i);
|
|
QRectF r = fm.boundingRect(str);
|
|
r.setWidth(fm.width(str)); // important, see docu!
|
|
r.moveTo(p1.x() - r.width() / 2., p1.y() - r.height() / 2.);
|
|
p.drawText(r, str, Qt::AlignHCenter | Qt::AlignVCenter);
|
|
}
|
|
|
|
// X-Achse
|
|
p.drawLine(m_trans2.map(QPointF(-m_scaleX, m_nullY)),
|
|
m_trans2.map(QPointF(m_scaleX + m_length, m_nullY)));
|
|
|
|
// kleine Striche
|
|
for (double i = m_scaleX; i <= m_length; i += m_scaleX)
|
|
{
|
|
const QPointF point = m_trans2.map(QPointF(i, m_nullY));
|
|
p.drawLine(QLineF(point.x(), point.y() - 2, point.x(), point.y() + 2));
|
|
}
|
|
|
|
// grosse Striche
|
|
for (double i = 0; i <= m_length; i += m_scaleX * 5)
|
|
{
|
|
const QPointF point = m_trans2.map(QPointF(i, m_nullY));
|
|
p.drawLine(QLineF(point.x(), point.y() - 4, point.x(), point.y() + 4));
|
|
}
|
|
|
|
for (double i = 0; i <= m_length; i += m_scaleX * 5)
|
|
{
|
|
if (qFuzzyCompare(i, m_nullX))
|
|
continue;
|
|
const QPointF point = m_trans2.map(QPointF(i, m_nullY));
|
|
const QPointF p1(point.x(), point.y() + 15);
|
|
const QString str = QString::number(i);
|
|
QRectF r = fm.boundingRect(str);
|
|
r.setWidth(fm.width(str)); // important, see docu!
|
|
r.moveTo(p1.x() - r.width() / 2., p1.y() - r.height() / 2.);
|
|
p.drawText(r, str, Qt::AlignHCenter | Qt::AlignVCenter);
|
|
}
|
|
p.end();
|
|
m_pixmap = QPixmap::fromImage(img);
|
|
}
|
|
|
|
void LtsHeightPlotWidget::Private::paintLines(QPainter &p) const
|
|
{
|
|
if (m_heightList.count() > 0)
|
|
{
|
|
// Mouse-Position zeichnen
|
|
QPointF pos = m_mousePos;
|
|
if (pos.x() < 0)
|
|
pos.setX(0);
|
|
if (pos.x() > m_heightList.at(m_heightList.count() - 1).first)
|
|
pos.setX(m_heightList.at(m_heightList.count() - 1).first);
|
|
|
|
//keine Transformation setzen da sonst die Linienstaerke des Pens veraendert wird!
|
|
//p.setTransform(d->m_transCombined);
|
|
const double curHeight = getDataHeight(pos.x());
|
|
p.setPen(m_mousePosPen);
|
|
p.drawLine(m_transCombined.map(QLineF(m_nullX, curHeight, pos.x(), curHeight)));
|
|
p.drawLine(m_transCombined.map(QLineF(pos.x(), m_nullY, pos.x(), curHeight)));
|
|
|
|
// Sichtlinie zeichnen
|
|
if (!m_mouseLeftClickPos.isNull())
|
|
{
|
|
const double y = curHeight > pos.y() ? curHeight : pos.y();
|
|
p.drawLine(m_transCombined.map(QLineF(m_nullX, y, pos.x(), y)));
|
|
p.drawLine(m_transCombined.map(QLineF(pos.x(), m_nullY, pos.x(), y)));
|
|
|
|
p.setPen(m_viewLinePen);
|
|
const QPointF &c = m_mouseLeftClickPos;
|
|
p.drawLine(m_transCombined.map(QLineF(m_nullX, c.y(), c.x(), c.y())));
|
|
p.drawLine(m_transCombined.map(QLineF(c.x(), m_nullY, c.x(), c.y())));
|
|
|
|
// nur hier da die anderen beiden Linien sonst nicht schoen aussehen
|
|
const QLineF line(m_mouseLeftClickPos, QPointF(pos.x(), y));
|
|
p.drawLine(m_transCombined.map(line));
|
|
}
|
|
}
|
|
}
|
|
|
|
LtsHeightPlotWidget::LtsHeightPlotWidget(QWidget *parent)
|
|
: QWidget(parent)
|
|
, d(new Private)
|
|
{
|
|
setMinimumSize(300, 300);
|
|
resize(size());
|
|
setMouseTracking(true);
|
|
}
|
|
|
|
LtsHeightPlotWidget::~LtsHeightPlotWidget()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
void LtsHeightPlotWidget::clearView()
|
|
{
|
|
d->clearPixmap();
|
|
update();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setData(const QVector< QPair< QPointF, double > > &data)
|
|
{
|
|
d->setData(data);
|
|
update();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setMarks(const QVector<QPointF> &data)
|
|
{
|
|
d->setMarks(data);
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setBackgroundBrush(const QBrush &brush)
|
|
{
|
|
QPalette pal = palette();
|
|
pal.setBrush(QPalette::Background, brush);
|
|
setPalette(pal);
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setTextFont(const QFont &f)
|
|
{
|
|
d->m_textFont = f;
|
|
d->repaint();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setAxisPen(const QPen &pen)
|
|
{
|
|
d->m_axisPen = pen;
|
|
d->repaint();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setPositionPen(const QPen &pen)
|
|
{
|
|
d->m_mousePosPen = pen;
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setViewLinePen(const QPen &pen)
|
|
{
|
|
d->m_viewLinePen = pen;
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setContourBrush(const QBrush &brush)
|
|
{
|
|
d->m_fillBrush = brush;
|
|
d->repaint();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::setMarkerPen(const QPen &pen)
|
|
{
|
|
d->m_markerPen = pen;
|
|
d->repaint();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::resizeEvent(QResizeEvent *e)
|
|
{
|
|
d->resize(size());
|
|
QWidget::resizeEvent(e);
|
|
}
|
|
|
|
void LtsHeightPlotWidget::paintEvent(QPaintEvent *e)
|
|
{
|
|
Q_UNUSED(e);
|
|
QPainter p(this);
|
|
|
|
const QPainter::RenderHints hints = QPainter::SmoothPixmapTransform |
|
|
QPainter::TextAntialiasing |
|
|
QPainter::Antialiasing;
|
|
p.setRenderHints(hints);
|
|
|
|
// vorgefertiges Bild zeichnen
|
|
p.drawPixmap(0, 0, d->m_pixmap);
|
|
|
|
// und jetzt die Hilfslinien
|
|
d->paintLines(p);
|
|
p.end();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::mouseMoveEvent(QMouseEvent *e)
|
|
{
|
|
QWidget::mouseMoveEvent(e);
|
|
if (!d->m_heightList.count())
|
|
return;
|
|
|
|
const QPointF pos = d->m_transInverted.map(e->localPos());
|
|
emit mousePositionChanged(d->getDataPos(pos.x()), d->getDataHeight(pos.x()), pos.y());
|
|
d->m_mousePos = pos;
|
|
update();
|
|
}
|
|
|
|
void LtsHeightPlotWidget::mouseReleaseEvent(QMouseEvent *e)
|
|
{
|
|
QWidget::mouseReleaseEvent(e);
|
|
if (!d->m_heightList.count())
|
|
return;
|
|
if (e->button() == Qt::LeftButton)
|
|
{
|
|
const QPointF &pos = d->m_mousePos;
|
|
if (pos.x() < 0)
|
|
return;
|
|
if (pos.x() > d->m_heightList.at(d->m_heightList.count() - 1).first)
|
|
return;
|
|
|
|
const double curHeight = d->getDataHeight(pos.x());
|
|
d->m_mouseLeftClickPos = QPointF(pos.x(), curHeight > pos.y() ? curHeight : pos.y());
|
|
emit startLineOfSight(d->getDataPos(pos.x()));
|
|
}
|
|
else if (e->button() == Qt::RightButton)
|
|
{
|
|
d->m_mouseLeftClickPos = QPointF();
|
|
emit stopLineOfSight();
|
|
update();
|
|
}
|
|
}
|
|
|