EnergySpectrumAnalyer/src/CustomQwtPlot.cpp

476 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CustomQwtPlot.h"
#include <QwtPlotCurve>
#include <QwtLegend>
#include <QwtPlotCanvas>
#include <QwtText>
#include <QwtPlotMarker>
#include <QwtPlotZoneItem>
#include <QwtScaleMap>
#include <QwtScaleDiv>
#include <QPen>
#include <QMouseEvent>
#include <QwtScaleWidget>
#include <QwtPlotPicker>
#include <QwtPlotShapeItem>
#include <QwtPickerDragRectMachine>
#include <QwtPlotMagnifier>
#include <QDebug>
CustomQwtPlotAxisPanner::CustomQwtPlotAxisPanner(QwtScaleWidget *scale_widget)
: QwtPlotPanner(scale_widget)
{
if (scale_widget) {
if (scale_widget->alignment() == QwtScaleDraw::BottomScale) {
this->setOrientations(Qt::Horizontal);
} else if (scale_widget->alignment() == QwtScaleDraw::LeftScale) {
this->setOrientations(Qt::Vertical);
} else if (scale_widget->alignment() == QwtScaleDraw::TopScale) {
this->setOrientations(Qt::Horizontal);
} else if (scale_widget->alignment() == QwtScaleDraw::RightScale) {
this->setOrientations(Qt::Vertical);
}
}
}
CustomQwtPlotAxisPanner::~CustomQwtPlotAxisPanner()
{
qDebug() << "~CustomQwtPlotXaxisPanner";
}
void CustomQwtPlotAxisPanner::moveCanvas(int dx, int dy)
{
QwtScaleWidget* scale_widget = dynamic_cast<QwtScaleWidget*>(this->canvas());
if (scale_widget) {
if (scale_widget->alignment() == QwtScaleDraw::BottomScale) {
QwtPlotPanner::moveCanvas(dx, 0);
} else if (scale_widget->alignment() == QwtScaleDraw::LeftScale) {
QwtPlotPanner::moveCanvas(0, dy);
} else if (scale_widget->alignment() == QwtScaleDraw::TopScale) {
QwtPlotPanner::moveCanvas(dx, 0);
} else if (scale_widget->alignment() == QwtScaleDraw::RightScale) {
QwtPlotPanner::moveCanvas(0, dy);
}
}
}
// CustomQwtPlotXaxisMagnifier::CustomQwtPlotXaxisMagnifier(QWidget *canvas)
// : QwtPlotMagnifier(canvas)
// {
// }
// CustomQwtPlotXaxisMagnifier::~CustomQwtPlotXaxisMagnifier()
// {
// qDebug() << "~CustomQwtPlotXaxisMagnifier";
// }
// void CustomQwtPlotXaxisMagnifier::rescale(double factor)
// {
// factor = qBound(0.1, factor, 10.0);
// QwtScaleMap x_map = plot()->canvasMap(QwtPlot::xBottom);
// double center = x_map.invTransform(plot()->canvas()->width() / 2);
// plot()->setAxisScale(
// QwtPlot::xBottom,
// center - (center - x_map.s1()) * factor,
// center + (x_map.s2() - center) * factor
// );
// plot()->replot();
// }
CustomQwtPlotXaxisSelector::CustomQwtPlotXaxisSelector(QWidget *canvas)
: QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,
QwtPicker::NoRubberBand,
QwtPicker::AlwaysOn,
canvas)
, _min_x(0.0)
, _max_x(0.0)
{
this->setStateMachine(new QwtPickerDragRectMachine());
this->setRubberBandPen(QPen(Qt::NoPen));
_overlay = new QwtPlotShapeItem;
_overlay->setRenderHint(QwtPlotItem::RenderAntialiased);
_overlay->setPen(QPen(Qt::red, 2));
_overlay->setBrush(QBrush(QColor(0, 120, 210, 50)));
_overlay->setZ(100);
_overlay->attach(plot());
_overlay->setVisible(false);
}
CustomQwtPlotXaxisSelector::~CustomQwtPlotXaxisSelector()
{
qDebug() << "~CustomQwtPlotXaxisSelector";
}
double CustomQwtPlotXaxisSelector::selectedMinX() const
{
return _min_x;
}
double CustomQwtPlotXaxisSelector::selectedMaxX() const
{
return _max_x;
}
void CustomQwtPlotXaxisSelector::clearSelection()
{
_min_x = 0.0;
_max_x = 0.0;
if (_overlay)
_overlay->setVisible(false);
}
void CustomQwtPlotXaxisSelector::move(const QPoint & pos)
{
QPolygon points = pickedPoints();
if (points.size() < 2) {
clearSelection();
return QwtPlotPicker::move(pos);
}
QPointF p1 = invTransform(points.first());
QPointF p2 = invTransform(points.last());
// 计算X范围
_min_x = qMin(p1.x(), p2.x());
_max_x = qMax(p1.x(), p2.x());
// Y轴铺满
double y_min = plot()->axisScaleDiv(QwtPlot::yLeft).lowerBound();
double y_max = plot()->axisScaleDiv(QwtPlot::yLeft).upperBound();
QRectF area(_min_x, y_min, _max_x - _min_x, y_max - y_min);
_overlay->setRect(area);
_overlay->setVisible(true);
plot()->replot();
QwtPlotPicker::move(pos);
}
bool CustomQwtPlotXaxisSelector::end(bool ok)
{
if (!ok) {
clearSelection();
return QwtPlotPicker::end(ok);
}
if (_overlay->isVisible()) {
_overlay->setVisible(false);
plot()->replot();
}
if ( (_max_x - _min_x) > 3 ) {
emit selectionFinished(_min_x, _max_x);
}
return QwtPlotPicker::end(ok);
}
CustomQwtPlot::CustomQwtPlot(QWidget *parent)
: QwtPlot(parent)
{
}
CustomQwtPlot::~CustomQwtPlot()
{
qDebug() << "~CustomQwtPlot";
}
void CustomQwtPlot::SetAxisDragScale(Axis axis_id, bool enable)
{
switch (axis_id) {
case xBottom: {
if ( enable ) {
if ( nullptr == _x_axis_panner ) {
_x_axis_panner = new CustomQwtPlotAxisPanner(this->axisWidget(QwtPlot::xBottom));
_x_axis_panner->setMouseButton(Qt::LeftButton);
_x_axis_panner->setAxisEnabled(QwtPlot::xBottom, true);
_x_axis_panner->setAxisEnabled(QwtPlot::yLeft, false);
} else {
_x_axis_panner->setAxisEnabled(QwtPlot::xBottom, true);
_x_axis_panner->setAxisEnabled(QwtPlot::yLeft, false);
}
if ( nullptr == _x_axis_magnifier ) {
_x_axis_magnifier = new QwtPlotMagnifier(this->axisWidget(QwtPlot::xBottom));
_x_axis_magnifier->setAxisEnabled(QwtPlot::xBottom, true);
_x_axis_magnifier->setAxisEnabled(QwtPlot::yLeft, false);
_x_axis_magnifier->setWheelFactor(1.1);
} else {
_x_axis_magnifier->setAxisEnabled(QwtPlot::xBottom, true);
_x_axis_magnifier->setAxisEnabled(QwtPlot::yLeft, false);
}
} else {
if (_x_axis_panner) {
delete _x_axis_panner;
_x_axis_panner = nullptr;
}
if (_x_axis_magnifier) {
delete _x_axis_magnifier;
_x_axis_magnifier = nullptr;
}
}
} break;
case yLeft: {
if ( enable ) {
if (nullptr == _y_axis_panner) {
_y_axis_panner = new CustomQwtPlotAxisPanner(this->axisWidget(QwtPlot::yLeft));
_y_axis_panner->setMouseButton(Qt::LeftButton);
} else {
_y_axis_panner->setAxisEnabled(QwtPlot::xBottom, false);
_y_axis_panner->setAxisEnabled(QwtPlot::yLeft, true);
}
if (nullptr == _y_axis_magnifier) {
_y_axis_magnifier = new QwtPlotMagnifier(this->axisWidget(QwtPlot::yLeft));
_y_axis_magnifier->setAxisEnabled(QwtPlot::xBottom, false);
_y_axis_magnifier->setAxisEnabled(QwtPlot::yLeft, true);
_y_axis_magnifier->setWheelFactor(1.1);
} else {
_y_axis_magnifier->setAxisEnabled(QwtPlot::xBottom, false);
_y_axis_magnifier->setAxisEnabled(QwtPlot::yLeft, true);
}
} else {
if (_y_axis_panner) {
delete _y_axis_panner;
_y_axis_panner = nullptr;
}
if (_y_axis_magnifier) {
delete _y_axis_magnifier;
_y_axis_magnifier = nullptr;
}
}
} break;
default:
break;
}
}
void CustomQwtPlot::SetAxisInitRange(Axis axis_id, double min, double max)
{
this->setAxisScale(axis_id, min, max);
if ( axis_id == QwtPlot::xBottom ) {
_init_x_min = min;
_init_x_max = max;
}
if ( axis_id == QwtPlot::yLeft ) {
_init_y_min = min;
_init_y_max = max;
}
}
void CustomQwtPlot::RegisterEventFilterFunc(std::function<bool (QObject *, QEvent *)> event_filter_func)
{
this->_event_filter_func_list.push_back(event_filter_func);
}
// void CustomQwtPlot::SetXaxisDragScale(bool enable)
// {
// QwtScaleWidget *x_scale = axisWidget(QwtPlot::xBottom);
// x_scale->setMouseTracking(enable);
// x_scale->installEventFilter(enable ? this : nullptr);
// }
void CustomQwtPlot::ResetPlot()
{
this->setAxisScale(QwtPlot::xBottom, _init_x_min, _init_x_max);
this->setAxisScale(QwtPlot::yLeft, _init_y_min, _init_y_max);
this->replot();
}
QwtPlotCurve *CustomQwtPlot::GetCurve(const QString &curve_name)
{
return _curves.value(curve_name, nullptr);
}
QList<QwtPlotCurve *> CustomQwtPlot::GetCurveList() const
{
return _curves.values();
}
void CustomQwtPlot::AddCurve(QwtPlotCurve *curve, bool auto_color)
{
if (curve) {
if ( auto_color ) {
curve->setPen(QPen(getDistinctColorForManyCurves(_curves.count()), 1));
}
curve->setZ(0);
curve->attach(this);
_curves[curve->title().text()] = curve;
}
}
QwtPlotMarker *CustomQwtPlot::GetMarker(const QString &marker_name, const QString &postion)
{
return _markers.value(marker_name).value(postion);
}
QList<QwtPlotMarker *> CustomQwtPlot::GetMarkerList() const
{
QList<QwtPlotMarker *> markers;
for (auto tmp_markers : this->_markers) {
markers.append(tmp_markers.values());
}
return markers;
}
void CustomQwtPlot::AddMarker(QwtPlotMarker *marker, const QString &marker_name, const QString &postion)
{
if (marker) {
QwtPlotCurve* curve = GetCurve(marker_name);
if (curve) {
QPen pen = curve->pen();
pen.setWidth(2);
marker->setLinePen(pen);
marker->setZ(20);
marker->attach(this);
_markers[marker_name][postion] = marker;
}
}
}
void CustomQwtPlot::RemoveMarker(const QString &marker_name, const QString &postion)
{
QwtPlotMarker* marker = GetMarker(marker_name, postion);
if (marker) {
marker->detach();
delete marker;
}
_markers[marker_name].remove(postion);
}
void CustomQwtPlot::CleanMarkers()
{
QList<QwtPlotMarker *> markers = GetMarkerList();
for (auto marker : markers) {
if (marker) {
marker->detach();
delete marker;
}
}
this->_markers.clear();
}
QwtPlotZoneItem* CustomQwtPlot::GetZoneItem(const QString& zone_item_name)
{
return _zone_items.value(zone_item_name);
}
QList<QwtPlotZoneItem *> CustomQwtPlot::GetZoneItemList() const
{
return this->_zone_items.values();
}
void CustomQwtPlot::AddZoneItem(QwtPlotZoneItem *zone_item, const QString &zone_item_name)
{
if (zone_item) {
zone_item->setPen(Qt::transparent); // 无边框
zone_item->setBrush(QColor(0, 120, 215, 95)); // 半透明蓝色RGBAA=80 透明度)
zone_item->setZ(10);
zone_item->attach(this);
_zone_items[zone_item_name] = zone_item;
}
}
void CustomQwtPlot::RemoveZoneItem(const QString& zone_item_name)
{
QwtPlotZoneItem* zone_item = GetZoneItem(zone_item_name);
if (zone_item) {
zone_item->detach();
delete zone_item;
}
_zone_items.remove(zone_item_name);
}
void CustomQwtPlot::CleanZoneItems()
{
QList<QwtPlotZoneItem *> zone_items = GetZoneItemList();
for (auto zone_item : zone_items) {
if (zone_item) {
zone_item->detach();
delete zone_item;
}
}
this->_zone_items.clear();
}
bool CustomQwtPlot::eventFilter(QObject *obj, QEvent *event)
{
bool has_filter = false;
for (auto filter : _event_filter_func_list) {
filter(obj, event);
has_filter = true;
}
if (has_filter) {
return true;
}
return QwtPlot::eventFilter(obj, event);
}
// void CustomQwtPlot::showEvent(QShowEvent *event)
// {
// Q_UNUSED(event);
// this->updateAxes();
// if ((0 == this->_init_x_max) && (0 == this->_init_y_max)) {
// // double x_min = this->axisScaleDiv(QwtPlot::xBottom).lowerBound();
// double x_max = this->axisScaleDiv(QwtPlot::xBottom).upperBound();
// // double y_min = this->axisScaleDiv(QwtPlot::yLeft).lowerBound();
// double y_max = this->axisScaleDiv(QwtPlot::yLeft).upperBound();
// this->_init_x_min = 0;
// this->_init_x_max = x_max;
// this->_init_y_min = 0;
// this->_init_y_max = y_max;
// this->setAxisScale(QwtPlot::xBottom, 0, x_max);
// }
// }
QColor getDistinctColorForManyCurves(int curve_index)
{
// 1. 定义基础色相覆盖不同主色系0-360度
const QList<int> base_hues = {
0, // 红色
30, // 橙色
60, // 黄色
90, // 黄绿色
120, // 绿色
150, // 青绿色
180, // 青色
210, // 天蓝色
240, // 蓝色
270, // 紫色
300, // 洋红色
330 // 玫红色
};
// 2. 定义不同的饱和度/明度组合(避免颜色太暗/太灰)
const QList<QPair<int, int>> sv_combinations = {
{85, 90}, // 高饱和、高明度
{70, 85}, // 中高饱和、中高明度
{85, 75}, // 高饱和、中明度
{60, 80}, // 中饱和、中高明度
{75, 70}, // 中高饱和、中明度
{90, 80} // 极高饱和、中高明度
};
// 3. 计算当前曲线对应的色相和饱和度/明度
int hue_index = curve_index % base_hues.size(); // 循环使用基础色相
int sv_index = (curve_index / base_hues.size()) % sv_combinations.size(); // 循环使用饱和度/明度组合
// 4. 获取HSV参数色相0-360饱和度0-255明度0-255
int hue = base_hues[hue_index];
int saturation = sv_combinations[sv_index].first * 255 / 100; // 转换为0-255范围
int value = sv_combinations[sv_index].second * 255 / 100; // 转换为0-255范围
// 5. 生成并返回颜色HSV转RGB
QColor color;
color.setHsv(hue, saturation, value);
// 额外优化:避免极浅/极暗的颜色(保证曲线可见)
if (value < 50 * 255 / 100) {
value = 50 * 255 / 100;
color.setHsv(hue, saturation, value);
}
return color;
}