EnergySpectrumAnalyer/src/CustomQwtPlot.cpp

476 lines
14 KiB
C++
Raw Normal View History

#include "CustomQwtPlot.h"
#include <QwtPlotCurve>
#include <QwtLegend>
#include <QwtPlotCanvas>
2026-03-12 20:23:55 +08:00
#include <QwtText>
#include <QwtPlotMarker>
#include <QwtPlotZoneItem>
#include <QwtScaleMap>
#include <QwtScaleDiv>
#include <QPen>
#include <QMouseEvent>
#include <QwtScaleWidget>
2026-03-17 10:50:33 +08:00
#include <QwtPlotPicker>
#include <QwtPlotShapeItem>
#include <QwtPickerDragRectMachine>
#include <QwtPlotMagnifier>
2026-03-17 10:50:33 +08:00
#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)
{
}
2026-03-17 10:50:33 +08:00
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();
}
2026-03-12 20:23:55 +08:00
QwtPlotCurve *CustomQwtPlot::GetCurve(const QString &curve_name)
{
2026-03-12 20:23:55 +08:00
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);
2026-03-12 20:23:55 +08:00
_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);
2026-03-12 20:23:55 +08:00
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;
}
}
2026-03-12 20:23:55 +08:00
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);
// }
// }
2026-03-17 10:50:33 +08:00
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;
}