DSCAnalysisTool/src/ui/centralwidget.cpp
2025-04-28 14:16:26 +08:00

941 lines
28 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 <QHBoxLayout>
#include <QRandomGenerator>
#include <cmath>
#include <limits>
#include <qcustomplot.h>
#include <QMessageBox>
#include "centralwidget.h"
#include "filemanager.h"
#include "pointcalculate.h"
#include "logger.h"
#include "xlsxhandler.h"
CentralWidget::CentralWidget(QWidget *parent)
: QWidget(parent)
,_customPlot(new LocalCustomPlot(this))
// ,_customPlot(new QCustomPlot(this))
,_analysisMode(AnalysisMode::Null)
,_currentCurve(nullptr)
{
setMouseTracking(true);
setStyleSheet("background-color: lightgray;");
resize(888, 666);
QHBoxLayout *layout = new QHBoxLayout();
layout->setMargin(0);
layout->addWidget(_customPlot);
this->setLayout(layout);
// 创建两条竖线
_line1 = new QCPItemStraightLine(_customPlot);
_line1->point1->setCoords(20, _customPlot->yAxis->range().lower);
_line1->point2->setCoords(20, _customPlot->yAxis->range().upper);
_line1->setPen(QPen(Qt::red));
_line1->setSelectable(true);
_line2 = new QCPItemStraightLine(_customPlot);
_line2->point1->setCoords(40, _customPlot->yAxis->range().lower);
_line2->point2->setCoords(40, _customPlot->yAxis->range().upper);
_line2->setPen(QPen(Qt::red));
_line2->setSelectable(true);
// 安装事件过滤器
// _graph = _customPlot->addGraph(0);
// _eventHandler = new EventHandler(_customPlot, _line1, _line2, _graph, nullptr);
_eventHandler = new EventHandler(_customPlot, _line1, _line2, nullptr);
_eventHandler->setEnable(true);
_customPlot->installEventFilter(_eventHandler);
_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
// _customPlot->setInteractions( QCP::iRangeZoom | QCP::iSelectPlottables);
// _customPlot->setInteractions(QCP::iSelectPlottables);
connect(_eventHandler,&EventHandler::sigSendLineXCoord,
this,&CentralWidget::sigSendLineXCoord);
setEventHandlerEnable(false);
//
#if 0
// init data
QVector<double> x(101), y(101);
for (int i = 0; i < 101; i++) {
x[i] = i / 50.0 - 1;//设置x的范围为-1~1
y[i] = x[i] * x[i];
}
_customPlot->graph(0)->setData(x, y);
//设置坐标轴标签
_customPlot->xAxis->setLabel("x coordinates");
_customPlot->yAxis->setLabel("y coordinates");
//设置坐标轴范围,以便我们可以看到全部数据
_customPlot->xAxis->setRange(0, 1);
_customPlot->yAxis->setRange(0, 100);
_customPlot->replot();
#endif
// 设置坐标轴标签
_customPlot->xAxis->setLabel("Temp/℃");
_customPlot->yAxis->setLabel("DSC/mW");
// 设置坐标轴范围,以便我们可以看到全部数据
_customPlot->xAxis->setRange(0,100);
_customPlot->yAxis->setRange(0,20);
// startTimer(300);
}
CentralWidget::~CentralWidget()
{
}
void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode)
{
_analysisMode = mode;
switch (mode)
{
case AnalysisMode::Null:
_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
break;
case AnalysisMode::NumericalLabel:
case AnalysisMode::StartPoint:
case AnalysisMode::StopPoint:
case AnalysisMode::PeakSynthesisAnalysis:
case AnalysisMode::GlassTransition:
_customPlot->setInteractions(QCP::iSelectPlottables);
setEventHandlerEnable(true);
break;
default:
break;
}
}
void CentralWidget::slotModeModify(const Global::Mode mode)
{
if (Global::Mode::Experiment == mode)
{
#if 0
if (_customPlot->graphCount() > 0 && _currentGraph)
{
// 清除第一个图表上的数据
_currentGraph->setData(QVector<double>(), QVector<double>());
}
#endif
// 创建画布,设置画布上的点数据
// _graph = _customPlot->addGraph();
// 设置坐标轴标签
_customPlot->xAxis->setLabel("Temp/℃");
_customPlot->yAxis->setLabel("DSC/mW");
// 设置坐标轴范围,以便我们可以看到全部数据
_customPlot->xAxis->setRange(0, 400);
_customPlot->yAxis->setRange(-20, 20);
}
else if (Global::Mode::Analysis == mode)
{
qDebug() << "file close...";
}
}
void CentralWidget::slotRecvCommonData(const CommonData &cd)
{
// logde<<"slotRecvCommonData...";
static double index = 0.0;
if(!_currentCurve){
logde<<"_currentCurve is nullptr";
_currentCurve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis);
}
// logde<<"temp:"<<cd.sample_temp<<",dsc:"<<cd.dsc;
_currentCurve->addData(index++,cd.sample_temp, cd.dsc);
// _customPlot->rescaleAxes();
_customPlot->replot();
// return;
// Record data.
if(!Global::_currentCurveExperimentDataPtr){
loger<<"_currentCurveExperimentDataPtr is nullptr.";
exit(0);
}else{
Global::ExperimentData ed;
ed.dsc = cd .dsc;
ed.sampleTemp = cd.sample_temp;
ed.runTime = cd.add_run_time;
ed.constantTempTime = cd.add_constan_temp_time;
Global::_currentCurveExperimentDataPtr->dataVtr.push_back(ed);
Global::_currentCurveExperimentDataPtr->curve = _currentCurve;
}
}
void CentralWidget::slotRecvAnalysisFileName(const QString &filePath)
{
qDebug() << "slotRecvAnalysisFileName" << filePath;
// todo.禁止重复文件添加。
Global::CurveFileData cfd;
if(XlsxHandler::readFile(filePath,cfd) != 0){
QMessageBox::warning((QWidget*)this->parent(), "warnning", "File parse error.");
return;
}
QFileInfo fileInfo(filePath);
cfd.fileName = fileInfo.fileName();
for(int i = 0;i < cfd.phaseTotalVtr.size();i++){
Global::PhaseTotalInfo& pti = cfd.phaseTotalVtr[i];
logde<<"data Vtr size:"<<pti.dataVtr.size();
PointCalculate::setExperimentData(pti.dataVtr);
QPair<QPointF,QPointF>startEndPointPair = PointCalculate::getStartAndEndPoint();
QPointF endPoint = startEndPointPair.second;
_customPlot->xAxis->setRange(0, endPoint.x() / 3 * 4);
//QPointF peakPoint = PointCalculate::getPeakPoint();
QPair<float, float> maxMinPair = PointCalculate::getMaxMinValue();
float absY = std::abs(maxMinPair.first - maxMinPair.second);
_customPlot->yAxis->setRange(- absY * 2,absY *2);
_customPlot->yAxis->setLabel("DSC/mW");
_customPlot->xAxis->setLabel("Temp/℃");
QVector<Global::ExperimentData> dataVtr;
QVector<double> tVtr,xVtr, yVtr;
int index = 0;
for (Global::ExperimentData &ed : pti.dataVtr)
{
tVtr.push_back(index++);
xVtr.push_back(ed.sampleTemp);
yVtr.push_back(ed.dsc);
}
_currentCurve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis);
_currentCurve->setData(tVtr, xVtr, yVtr);
_currentCurve->setSelectable(QCP::stWhole); // 设置曲线可选
pti.curve = _currentCurve;
}
// Add data to global parameter.
Global::_curveFileDataVtr.push_back(cfd);
_customPlot->rescaleAxes();
_customPlot->replot();
}
void CentralWidget::slotAnalysisSettingApply()
{
switch (_analysisMode) {
case AnalysisMode::NumericalLabel:
{
QPointF selectPoint = PointCalculate::getClosestPointByX(
_line1->point1->coords().x());
logde<<"lin1 x:"<<_line1->point1->coords().x();
if(selectPoint.isNull()){
QMessageBox::warning((QWidget*)this->parent(), "warnning", "曲线选择错误.");
return;
}
drawText(selectPoint,
PointCalculate::textFormatNumbericalLabel(selectPoint));
break;
}
case AnalysisMode::StartPoint:
case AnalysisMode::StopPoint:{
double x1 = _line1->point1->coords().x();
double x2 = _line2->point1->coords().x();
PointCalculate::setRegionPointX(x1,x2);
QPair<QPointF, QPointF> startEndPointPair =
PointCalculate::calculateStartAndEndPoint();
if(_analysisMode == AnalysisMode::StartPoint){
drawText(startEndPointPair.first,
PointCalculate::textFormatStartPoint(startEndPointPair.first));
}else{
drawText(startEndPointPair.second,
PointCalculate::textFormatEndPoint(startEndPointPair.second));
}
break;
}
case AnalysisMode::PeakSynthesisAnalysis:
{
double x1 = _line1->point1->coords().x();
double x2 = _line2->point1->coords().x();
fillGraph(x1,x2);
PointCalculate::setRegionPointX(x1,x2);
//enthalpy
double sampleWeight = 0.0f;
for(Global::CurveFileData& cfd:Global::_curveFileDataVtr){
for(Global::PhaseTotalInfo& pti:cfd.phaseTotalVtr){
if(_currentCurve && _currentCurve == pti.curve){
sampleWeight = cfd.ei.sampleWeight.toDouble();
}
}
}
logde<<"sample weight:"<<sampleWeight;
double enthalpyValue = PointCalculate::calculateArea() / sampleWeight;
//peak
QPointF peakPoint = PointCalculate::getPeakPoint();
//start point and end point
QPair<QPointF, QPointF> startEndPointPair =
PointCalculate::calculateStartAndEndPoint();
logde<<"start,end:"<<startEndPointPair.first.x()<<","
<<startEndPointPair.second.x();
drawText(peakPoint,
PointCalculate::textFormatPeakPoint(enthalpyValue,
peakPoint.x(),
startEndPointPair.first.x(),
startEndPointPair.second.x()));
//
break;
}
case AnalysisMode::GlassTransition:
{
// glassTransitionHandle();
glassTransitionHandle2();
//
break;
}
default:
break;
}
}
void CentralWidget::slotAnalysisSettingConfirm()
{
slotAnalysisSettingApply();
setAnalysisMode(CentralWidget::AnalysisMode::Null);
_line1->setVisible(false);
_line2->setVisible(false);
emit sigRightDockWidgetHide();
}
void CentralWidget::slotAnalysisSettingUndo()
{
clearData(ClearDataMode::Undo);
}
void CentralWidget::slotAnalysisSettingCancel()
{
clearData(ClearDataMode::Undo);
setAnalysisMode(CentralWidget::AnalysisMode::Null);
_line1->setVisible(false);
_line2->setVisible(false);
emit sigRightDockWidgetHide();
}
void CentralWidget::slotAnalysisSettingLineXPoint(const int index, const double)
{
}
void CentralWidget::slotDrawCustomText(const QString str)
{
QCPItemText* customLegendItem = new QCPItemText(_customPlot);
customLegendItem->position->setTypeX(QCPItemPosition::ptAbsolute);
customLegendItem->position->setTypeY(QCPItemPosition::ptAbsolute);
customLegendItem->position->setCoords(150, 50); // 稍微向下移动
customLegendItem->setText(str);
QFont font("Arial", 10);
customLegendItem->setFont(font);
// 设置边框和背景
customLegendItem->setPen(QPen(Qt::black));
customLegendItem->setBrush(QBrush(Qt::white));
// 禁止点选
customLegendItem->setSelectable(false);
customLegendItem->setObjectName("fixed");
_customPlot->replot();
}
void CentralWidget::timerEvent(QTimerEvent *event)
{
_customPlot->replot();
#if 0
// key的单位是秒
double key = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0;
// 添加数据
// 使用随机数产生一条曲线
// double value0 = realDataI();
double value0 = QRandomGenerator::global()->bounded(10.123);
_customPlot->graph(0)->addData(key, value0); // 添加数据到曲线
// 删除8秒之前的数据。这里的8要和下面设置横坐标宽度的8配合起来
// 才能起到想要的效果,可以调整这两个值,观察显示的效果。
_customPlot->graph(0)->data()->remove(key - 80);
// 自动设定graph(1)曲线y轴的范围如果不设定有可能看不到图像
// 也可以用ui->customPlot->yAxis->setRange(up,low)手动设定y轴范围
_customPlot->graph(0)->rescaleValueAxis(true);
// 这里的8是指横坐标时间宽度为8秒如果想要横坐标显示更多的时间
// 就把8调整为比较大到值比如要显示60秒那就改成60。
// 这时removeDataBefore(key-8)中的8也要改成60否则曲线显示不完整。
_customPlot->yAxis->setRange(0, 20); // 设定x轴的范围
_customPlot->xAxis->setRange(key + 0.25, 80, Qt::AlignRight); // 设定x轴的范围
_customPlot->replot();
#endif
}
void CentralWidget::contextMenuEvent(QContextMenuEvent *event)
{
qDebug()<<"left menu...";
QPoint point = event->globalPos();
emit sigContextMenuShow(point);
}
void CentralWidget::glassTransitionHandle()
{
QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x());
QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x());
logde<<"point1:"<<point1.x()<<","<<point1.y();
logde<<"point2:"<<point2.x()<<","<<point2.y();
#if 0
QCPItemStraightLine *line1 = new QCPItemStraightLine(_customPlot);
line1->point1->setCoords(point1.x() - 5,point1.y());
line1->point2->setCoords(point1.x() + 5,point1.y());
line1->setPen(QPen(Qt::darkRed));
line1->setSelectable(false);
line1->setVisible(true);
QCPItemStraightLine *line2 = new QCPItemStraightLine(_customPlot);
line2->point1->setCoords(point2.x() - 5,point2.y());
line2->point2->setCoords(point2.x() + 5,point2.y());
line2->setPen(QPen(Qt::darkGreen));
line2->setSelectable(false);
line2->setVisible(true);
_customPlot->replot();
#endif
//
PointCalculate::Line lineStrc1,lineStrc2,tangetLineStrc;
lineStrc1.slope = 0.0;
lineStrc1.intercept = point1.y();
lineStrc2.slope = 0.0;
lineStrc2.intercept = point2.y();
QPair<float,float> tangentLinePair = PointCalculate::getCurveInflectionPointTangent(point1.x(),point2.x());
tangetLineStrc.slope = tangentLinePair.first;
tangetLineStrc.intercept = tangentLinePair.second;
QPointF intersection1 = PointCalculate::getIntersection(tangetLineStrc,lineStrc1);
QPointF intersection2 = PointCalculate::getIntersection(tangetLineStrc,lineStrc2);
// logde<<"intersection1 x:"<<intersection1.x();
// logde<<"intersection2 x:"<<intersection2.x();
//
float averageY = (point1.y() + point2.y()) /2;
logde<<"average Y:"<<averageY;
QPointF averagePoint = PointCalculate::getClosestPointByY(point1.x(),point2.x(),averageY);
// logde<<"average y:"<<averageY;
logde<<"averagePoint x,y:"<<averagePoint.x()<<","
<<averagePoint.y();
logde<<"glass T1:"<<intersection1.x()
<<",Tg:"<<averagePoint.x()
<<",T2:"<<intersection2.x();
QString str = PointCalculate::textFormatGlassTranstion(intersection2.x(),
averagePoint.x(),
intersection1.x());
//draw line
///line1
QVector<double> xVtr,yVtr;
xVtr.push_back(intersection1.x());
xVtr.push_back(point1.x());
yVtr.push_back(intersection1.y());
yVtr.push_back(point1.y());
QCPGraph *lineGraph1 = _customPlot->addGraph();
lineGraph1->setData(xVtr, yVtr);
_customPlot->replot();
///line2
QVector<double> xVtr2,yVtr2;
xVtr2.push_back(intersection2.x());
xVtr2.push_back(point2.x());
yVtr2.push_back(intersection2.y());
yVtr2.push_back(point2.y());
QCPGraph *lineGraph2 = _customPlot->addGraph();
lineGraph2->setData(xVtr2, yVtr2);
_customPlot->replot();
//draw text
drawText(averagePoint,str);
_customPlot->replot();
#if 0
// 创建一个圆形绘图项
QCPItemEllipse *circle = new QCPItemEllipse(_customPlot);
// _customPlot->addItem(circle);
// 设置圆形的位置和大小
circle->topLeft->setCoords(-5, 5);
circle->bottomRight->setCoords(5, -5);
// 设置圆形的填充和边框颜色
circle->setBrush(QBrush(Qt::cyan));
circle->setPen(QPen(Qt::blue));
#endif
#if 0
QCPItemStraightLine *line3 = new QCPItemStraightLine(_customPlot);
line3->point1->setCoords(averagePoint.x() + 1,averagePoint.y() + 1);
line3->point2->setCoords(averagePoint.x() - 1,averagePoint.y() - 1);
line3->setPen(QPen(Qt::black));
line3->setSelectable(false);
line3->setVisible(true);
_customPlot->replot();
#endif
}
void CentralWidget::glassTransitionHandle2()
{
QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x());
QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x());
logde<<"point1:"<<point1.x()<<","<<point1.y();
logde<<"point2:"<<point2.x()<<","<<point2.y();
QVector<QPointF> point1Vtr = PointCalculate::getNearbyPointGroupByX(point1.x());
QVector<QPointF> point2Vtr = PointCalculate::getNearbyPointGroupByX(point2.x());
QVector<double> xVtr,yVtr;
for(QPointF &p:point1Vtr){
xVtr.append(p.x());
yVtr.append(p.y());
}
PointCalculate::Line line1 = calculateLinearRegression(xVtr,yVtr);
#if 1
///line1
// QVector<double> xVtr,yVtr;
xVtr.clear();
yVtr.clear();
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
xVtr.push_back(point1.x() + 10);
double y1 = line1.slope * (point1.x() + 10) + line1.intercept;
yVtr.push_back(y1);
QCPGraph *lineGraph1 = _customPlot->addGraph();
lineGraph1->setData(xVtr, yVtr);
QPen pen;
pen.setColor(Qt::darkGreen);
lineGraph1->setPen(pen);
#endif
xVtr.clear();
yVtr.clear();
for(QPointF &p:point2Vtr){
xVtr.append(p.x());
yVtr.append(p.y());
}
PointCalculate::Line line2 = calculateLinearRegression(xVtr,yVtr);
#if 1
///line2
QVector<double> xVtr2,yVtr2;
xVtr2.push_back(point2.x());
yVtr2.push_back(point2.y());
xVtr2.push_back(point2.x() - 10);
double y2 = line2.slope * (point2.x() - 10) + line2.intercept;
yVtr2.push_back(y2);
QCPGraph *lineGraph2 = _customPlot->addGraph();
lineGraph2->setData(xVtr2, yVtr2);
lineGraph2->setPen(pen);
_customPlot->replot();
#endif
// inflection point.
QVector<QPointF> originalPointVtr = PointCalculate::getPointVtrInXRange(point1.x(),point2.x());
// QVector<QPointF> pointVtr = PointCalculate::movingAveragePoint(originalPointVtr,3);
QVector<QPointF> pointVtr = originalPointVtr;
xVtr.clear();
yVtr.clear();
for(QPointF& p:pointVtr){
xVtr.append(p.x());
yVtr.append(p.y());
}
QMap<double, PointCalculate::Line> tangentLines =
PointCalculate::calculateTangentLine(xVtr,yVtr);
double targetX = 0.0;
PointCalculate::Line targetLine;
double maxSlopeAbs = 0.0; // 初始化最大斜率绝对值为0
#if 0
for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) {
if (std::fabs(it.value().slope) > maxSlopeAbs) {
maxSlopeAbs = std::fabs(it.value().slope); // 更新最大斜率绝对值
targetX = it.key();
targetLine = it.value();
}
}
#endif
// new method
for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) {
if (std::fabs(it.value().slope) > maxSlopeAbs) {
maxSlopeAbs = std::fabs(it.value().slope); // 更新最大斜率绝对值
targetX = it.key();
targetLine = it.value();
}
}
int index = 0;
QPointF prePoint,currentPoint,lastPoint;
for (int i = 0;i < pointVtr.size();i++) {
currentPoint = pointVtr[i];
if(currentPoint.x() == targetX){
index = i;
break;
}
}
prePoint = pointVtr[index - 1];
lastPoint = pointVtr[index + 1];
targetLine.slope = PointCalculate::calculateSlope(lastPoint.x(),lastPoint.y(),prePoint.x(),prePoint.y());
targetLine.intercept = currentPoint.y() - targetLine.slope * currentPoint.x();
//
#if 1
QPointF intersection1 = PointCalculate::getIntersection(targetLine,line1);
QPointF intersection2 = PointCalculate::getIntersection(targetLine,line2);
// graph 3
xVtr.clear();
yVtr.clear();
#if 0
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
#endif
#if 1
xVtr.push_back(intersection1.x());
yVtr.push_back(intersection1.y());
xVtr.push_back(intersection2.x());
yVtr.push_back(intersection2.y());
#endif
QCPGraph *lineGraph3 = _customPlot->addGraph();
lineGraph3->setData(xVtr, yVtr);
lineGraph3->setPen(pen);
#endif
_customPlot->replot();
// point value
double averageY = (point1.y() + point2.y()) / 2;
QPointF averagePoint = PointCalculate::getClosestPointByY(point1.x(),point2.x(),averageY);
QString str = PointCalculate::textFormatGlassTranstion(intersection1.x(),
averagePoint.x(),
intersection2.x());
drawText(averagePoint,str);
}
// 使用最小二乘法计算线性回归
PointCalculate::Line CentralWidget::calculateLinearRegression(const QVector<double>& x, const QVector<double>& y) {
PointCalculate::Line line;
double sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
size_t n = x.size();
// 计算所需的总和
for (size_t i = 0; i < n; ++i) {
sum_x += x[i];
sum_y += y[i];
sum_xy += x[i] * y[i];
sum_xx += x[i] * x[i];
}
// 计算斜率和截距
double x_mean = sum_x / n;
double y_mean = sum_y / n;
double numerator = n * sum_xy - sum_x * sum_y;
double denominator = n * sum_xx - sum_x * sum_x;
line.slope = numerator / denominator;
line.intercept = y_mean - line.slope * x_mean;
return line;
}
// 二次多项式拟合函数
void CentralWidget::quadraticFit(const QVector<QPointF>& points, double& a, double& b, double& c) {
int n = points.size();
if (n < 3) {
throw std::invalid_argument("At least three points are required for quadratic fit.");
}
double sumX = 0, sumY = 0, sumXX = 0, sumXY = 0, sumX2Y = 0;
for (const QPointF& p : points) {
sumX += p.x();
sumY += p.y();
sumXX += p.x() * p.x();
sumXY += p.x() * p.y();
sumX2Y += p.x() * p.x() * p.y();
}
double det = n * (sumXX * sumY - sumX * sumXY) - sumX * sumX * sumY + sumX * sumX2Y;
a = (sumXX * sumY - sumX * sumXY) / det;
b = (sumX2Y - n * sumXY) / det;
c = (sumY - a * sumX - b * sumX) / n;
}
// 计算二次多项式拟合曲线的导数(切线斜率)
double CentralWidget::derivativeAt(const double a, const double b, const double x) {
return 2 * a * x + b;
}
void CentralWidget::setEventHandlerEnable(const bool flag)
{
logde<<"setEventHandlerEnable..."<<flag;
// line visiable func
auto lineVisiableFunc = [&](QCPItemStraightLine* line){
line->setSelected(flag);
line->setVisible(flag);
};
// todo. 当竖线隐藏时,需要设置不可选择模式。
// _eventHandler->setEnable(flag);
#if 1
// move line to suitable position.
double xMax = _customPlot->xAxis->range().upper;
double xMin = _customPlot->xAxis->range().lower;
// logde<<"xMax:"<<xMax;
// QVector<double> ticks = _customPlot->xAxis->tickVector();
// int numTicks = ticks.size();
// logde<<"ticks:"<<numTicks;
double range = xMax - xMin;
double xLeft = xMin + range / 3;
double xRight = xMin + range * 2 / 3;
_line1->point1->setCoords(xLeft,_line1->point1->coords().y());
_line1->point2->setCoords(xLeft,_line1->point2->coords().y());
_line2->point1->setCoords(xRight,_line2->point1->coords().y());
_line2->point2->setCoords(xRight,_line2->point2->coords().y());
#endif
lineVisiableFunc(_line1);
if(AnalysisMode::NumericalLabel != _analysisMode){
lineVisiableFunc(_line2);
}
//
_customPlot->replot();
}
QPointF CentralWidget::getTheCoordinatesOfTheTextBox(const QPointF point)
{
double xMax = _customPlot->xAxis->range().upper;
double xMin = _customPlot->xAxis->range().lower;
logde<<"xMax:"<<xMax;
QVector<double> ticks = _customPlot->xAxis->tickVector();
int numTicks = ticks.size();
logde<<"ticks:"<<numTicks;
double distance = (xMax - xMin) / ticks.size();
return QPointF(point.x() + distance,point.y());
}
void CentralWidget::drawText(const QPointF point, const QString text)
{
QPointF textBoxPoint = getTheCoordinatesOfTheTextBox(point);
// 创建标注文字QCPItemText
QCPItemText *textLabel = new QCPItemText(_customPlot);
textLabel->setPositionAlignment(Qt::AlignCenter); // 对齐方式
textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标
textLabel->position->setCoords(textBoxPoint.x(),textBoxPoint.y()); // 设置文本位置在指定点上方
textLabel->setText(text); // 设置文本内容
QFont font(QFont("Arial", 10));
textLabel->setFont(font);
textLabel->setSelectedFont(font);
textLabel->setSelectable(true); // 设置为可选
// 创建指向点的线段QCPItemLine
QCPItemLine *arrow = new QCPItemLine(_customPlot);
arrow->start->setParentAnchor(textLabel->left); // 线段起点绑定到标注文字底部
arrow->end->setCoords(point.x(),point.y()); // 线段终点设置为指定的点
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
arrow->setPen(QPen(Qt::red, 1));
// 重绘图表以显示文本标签和箭头
_customPlot->replot();
}
void CentralWidget::fillGraph(const double x1, const double x2)
{
double y1 = PointCalculate::getClosestPointByX(x1).y();
double y2 = PointCalculate::getClosestPointByX(x2).y();
QVector<double> xVtr,yVtr;
xVtr.push_back(x1);
xVtr.push_back(x2);
yVtr.push_back(y1);
yVtr.push_back(y2);
QCPGraph *mainGraph = _customPlot->addGraph();
mainGraph->setData(xVtr, yVtr);
mainGraph->setPen(QPen(Qt::red, 1));
QVector<Global::ExperimentData> curveDataVtr =
PointCalculate::getDataInXRange(x1,x2);
QCPGraph *fillGraph = _customPlot->addGraph();
QVector<double> fillX, fillY;
for(int i = 0;i < curveDataVtr.size();i++){
Global::ExperimentData &ed = curveDataVtr[i];
fillX<<ed.sampleTemp;
fillY<<ed.dsc;
}
fillGraph->setData(fillX, fillY);
fillGraph->setBrush(QBrush(Qt::green, Qt::SolidPattern));
fillGraph->setChannelFillGraph(mainGraph);
_customPlot->replot();
}
void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
{
if(mode == ClearDataMode::All){
// Clear the data of graph.
for (int i = _customPlot->plottableCount() - 1; i >= 0; --i) {
QCPAbstractPlottable* plottable = _customPlot->plottable(i);
if (auto curve = dynamic_cast<QCPCurve*>(plottable)) {
_customPlot->removePlottable(curve);
}
}
// Clear data.
Global::_curveExperimentDataVtr.clear();
// Set lines visiable false.
_line1->setVisible(false);
_line2->setVisible(false);
}
#if 1
// Clear graph on plot.
for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
QCPGraph *graph = _customPlot->graph(i);
_customPlot->removeGraph(graph);
}
_currentCurve = nullptr;
#endif
// Delete items.
QList<QCPAbstractItem *> itemsToKeep;
itemsToKeep << _line1 << _line2;
for (int i = _customPlot->itemCount() - 1; i >= 0; --i) {
QCPAbstractItem *item = _customPlot->item(i);
if (!itemsToKeep.contains(item)) {
_customPlot->removeItem(item);
}
}
// 重绘图表以显示更改
_customPlot->replot();
}
void CentralWidget::clearAllData()
{
clearData(ClearDataMode::All);
}
QPixmap CentralWidget::getPixMap()
{
return _customPlot->toPixmap();
}
void CentralWidget::slotAxisModify(const float temp)
{
_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
float value = temp + 20;
_customPlot->xAxis->setRange(10,value);
_customPlot->yAxis->setRange(-5,5);
}