#include "plotwidget.h" #include "xlsxdocument.h" extern QStringList slist_temper; extern QStringList slist_dsc; extern QString g_sname_string; extern double g_quality; double g_area; double g_kmin; double g_b_tang1; double g_target_x1; double g_target_y1; double g_kmax; double g_b_tang2; double g_target_x2; double g_target_y2; PlotWidget::PlotWidget(QWidget *parent) : QWidget(parent) { qRegisterMetaType("QVariant"); m_xlsx = new QXlsx::Document(this); m_customPlot = new QCustomPlot(this); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(m_customPlot); m_label_left = new QLabel(this); m_label_left->setGeometry(80, 70, 60, 20); m_label_left->setText(QObject::tr("左选线:")); m_lineEdit_left = new QLineEdit(this); m_lineEdit_left->setGeometry(130, 70, 60, 20); m_label_right = new QLabel(this); m_label_right->setText(QObject::tr("右选线:")); m_label_right->setGeometry(80, 100, 60, 20); m_lineEdit_right = new QLineEdit(this); m_lineEdit_right->setGeometry(130, 100, 60, 20); m_clear_button = new QPushButton(this); m_clear_button->setText(QObject::tr("清除曲线")); m_clear_button->setGeometry(80, 130, 110, 20); // m_save_button = new QPushButton(this); // m_save_button->setText(QObject::tr("保存数据")); // m_save_button->setGeometry(80, 152, 110, 20); ///m_itemLine = new QCPItemLine(m_customPlot); m_count_graph = 0; setupPlot(); plotWaterfall(); //建立槽函数 connect(m_customPlot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress(QMouseEvent*))); connect(m_customPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove(QMouseEvent*))); connect(m_customPlot, SIGNAL(mouseRelease(QMouseEvent*)), this, SLOT(mouseRelease())); connect(m_customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged())); connect(this, SIGNAL(send_line_data_to_plot(QVariant, QVariant)), this, SLOT(plot_connect_line(QVariant, QVariant))); connect(this, SIGNAL(show_min_point(double, double)), this, SLOT(show_min_point_text(double, double))); // connect(m_customPlot,&QCustomPlot::mouseDoubleClick,this,[=]{ //双击效果不理想 // m_customPlot->rescaleAxes(); // // m_customPlot->xAxis->rescale(); // // m_customPlot->yAxis->rescale(); // m_customPlot->replot(); // }); connect(m_clear_button, SIGNAL(clicked()), this, SLOT(clear_all_graph())); ///connect(m_save_button, SIGNAL(clicked()), this, SLOT(save_sample_quality_area_data())); m_customPlot->xAxis->setRange(0, 1000, Qt::AlignCenter); m_customPlot->yAxis->setRange(0, 1000, Qt::AlignCenter); ///m_customPlot->legend->setVisible(true); ///m_customPlot->legend->setSelectableParts(QCPLegend::spItems);//图例本身不能被选择,只有里面的项可以被选择 ///m_customPlot->legend->setSelectedIconBorderPen(Qt::NoPen); } PlotWidget::~PlotWidget() { delete m_customPlot; delete m_label_left; delete m_label_right; delete m_lineEdit_left; delete m_lineEdit_right; } void PlotWidget::show_min_point_text(double x_min, double y_min) { if(m_count_graph>0) { m_minValueText->setText(QString("峰信息:\n焓值:\n峰值:%1\n起始点:\n终止点:").arg(x_min));///.arg(y_min)); m_minValueText->setPen(QPen(Qt::green)); //字体颜色 m_minValueText->setColor(Qt::green); m_minValueText->setVisible(true); m_minValueText->setSelectable(true); ///m_minValueText->setFlag(QCPItemText::ItemIsMovable); ///m_minValueText->setMovable(true); m_minValueText->position->setCoords(x_min, y_min); m_customPlot->replot(); } } void PlotWidget::plot_connect_line(QVariant varx, QVariant vary) { if(m_count_graph>0) { QPen graphPen; graphPen.setColor(QColor(40, 255, 110, 250)); graphPen.setWidthF(3.0); m_customPlot->addGraph(); m_customPlot->graph()->setPen(graphPen); m_customPlot->graph()->setBrush(QBrush(QColor(0, 0, 255, 60))); ///m_customPlot->graph()->setBrush(Qt::NoBrush); QVector vx1 = varx.value< QVector >(); QVector vy1 = vary.value< QVector >(); m_count_graph++; m_customPlot->graph(m_count_graph)->setData(vx1, vy1); m_customPlot->graph(m_count_graph)->setChannelFillGraph(m_customPlot->graph(m_count_graph-1)); m_customPlot->legend->setVisible(false); m_customPlot->legend->setSelectableParts(QCPLegend::spItems); m_customPlot->axisRect()->setupFullAxesBox(true); m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom| QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables | QCP::iMultiSelect | QCP::iSelectItems); m_customPlot->replot(); } } void PlotWidget::save_sample_quality_area_data() { m_xlsx->addSheet(g_sname_string); m_xlsx->setColumnWidth(1,4);//第1行,6列宽 m_xlsx->write(1,1, g_sname_string); m_xlsx->write(1,2, g_quality); m_xlsx->write(1,3, g_area); m_xlsx->write(1,4, g_target_x1); m_xlsx->saveAs(QDir::currentPath() + "/sample.ana"); QMessageBox::information(this,"提示","保存成功!"); } void PlotWidget::clear_all_graph() { int count=m_customPlot->graphCount();//获取曲线条数 // for(int i=1;iremoveGraph(i); // } for(int i=count-1;i>=1;i--) { m_customPlot->removeGraph(i); } m_minValueText->setVisible(false); if(1==count) m_clear_button->setDisabled(true); m_lineLV->setVisible(false); m_lineRV->setVisible(false); m_count_graph = 0; m_customPlot->replot(); } void PlotWidget::selectionChanged() { // synchronize selection of graphs with selection of corresponding legend items: for (int i=0; igraphCount(); ++i) { QCPGraph *graph = m_customPlot->graph(i); QCPPlottableLegendItem *item = m_customPlot->legend->itemWithPlottable(graph); if (item->selected() || graph->selected()) { item->setSelected(true); //注意:这句需要Qcustomplot2.0系列版本 graph->setSelection(QCPDataSelection(graph->data()->dataRange())); //这句1.0系列版本即可 ///graph->setSelected(true); } } } void PlotWidget::replot_xlsx_data() { // The following plot setup is mostly taken from the plot demos: QPen graphPen; ///graphPen.setColor(QColor(std::rand()%245+10, std::rand()%245+10, std::rand()%245+10)); graphPen.setColor(QColor(130, 40, 160)); graphPen.setWidthF(2.0); m_customPlot->addGraph(); ///m_customPlot->graph()->setPen(QPen(Qt::blue)); m_customPlot->graph()->setPen(graphPen); ///m_customPlot->graph()->setBrush(QBrush(QColor(0, 0, 255, 20))); m_customPlot->graph()->setBrush(Qt::NoBrush); mutex.lock(); if(slist_temper.size()!=slist_dsc.size()) return; QVector x(slist_temper.size()), y0(slist_dsc.size()); for(int i = 0; i < slist_temper.size(); ++i) { ///qDebug() << slist_temper.at(i).toDouble()<graph(m_count_graph)->setData(x, y0); m_customPlot->graph(m_count_graph)->rescaleAxes(); //适应图形比例 ///m_customPlot->graph(3)->setData(x, y1); m_customPlot->axisRect()->setupFullAxesBox(true); m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom| QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables | QCP::iMultiSelect | QCP::iSelectItems); m_customPlot->replot(); m_clear_button->setDisabled(false); emit calcu_button_enable(); } void PlotWidget::setupPlot() { m_minValueText = new QCPItemText(m_customPlot); ///minValueText->setLayer("overlay"); m_minValueText->setText("峰值"); m_minValueText->setVisible(false); m_minValueText->setSelectable(true); ///m_minValueText->position->setCoords( , ); m_tracer = new QCPItemTracer(m_customPlot); //初始化锚点 m_tracer->setInterpolating(false); m_tracer->setStyle(QCPItemTracer::tsCircle); m_tracer->setPen(QPen(Qt::red)); m_tracer->setBrush(Qt::red); m_tracer->setSize(6); m_tracer->setVisible(false); // The following plot setup is mostly taken from the plot demos: m_customPlot->addGraph(); m_customPlot->graph()->setPen(QPen(Qt::green)); m_customPlot->graph()->setBrush(QBrush(QColor(0, 0, 255, 20))); QVector x(500), y0(500), y1(500); for (int i=0; i<500; ++i) { x[i] = (i/499.0-0.5)*1000; y0[i] = qExp(-x[i]*x[i]*0.25)*qSin(x[i]*5)*50; y1[i] = qExp(-x[i]*x[i]*0.25)*50; } m_customPlot->graph(0)->setData(x, y0); m_customPlot->legend->setVisible(false); m_customPlot->legend->setSelectableParts(QCPLegend::spItems); m_customPlot->axisRect()->setupFullAxesBox(true); m_customPlot->xAxis->setLabel("Temp"); m_customPlot->yAxis->setLabel("DSC"); m_customPlot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);//x轴终点箭头图案 m_customPlot->xAxis->setLowerEnding(QCPLineEnding::esDisc); //x轴起点圆点图案 m_customPlot->yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);//y轴终点小方块图案 m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom| QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables | QCP::iMultiSelect | QCP::iSelectItems); ///m_customPlot->clearGraphs(); for (int i=0; i< m_customPlot->graphCount(); ++i) { QCPGraph *graphItem = m_customPlot->graph(i); ///if (graphItem->selected()) ///{ graphItem->setVisible(false); ///} } m_customPlot->replot(); } void PlotWidget::show_line_cursor() { m_lineLV->setVisible(true); m_lineRV->setVisible(true); m_customPlot->replot(); } void PlotWidget::hide_line_cursor() { m_lineLV->setVisible(false); m_lineRV->setVisible(false); m_customPlot->replot(); } /******************* * @author xxx * @method * @param * 初始化游标 *******************/ void PlotWidget::plotWaterfall() { try { //默认曲线选择 ///graph = customPlot->graph(0); ///graph = ui->plot->graph(); //设置游标初始位置(可以不设置) ///QCPRange keyRange = customPlot->axisRect()->axis(QCPAxis::atBottom)->range(); QCPRange keyRange = m_customPlot->axisRect()->axis(QCPAxis::atBottom)->range(); // xValue1 = keyRange.upper * 0.2; // xValue2 = keyRange.upper * 0.7; xValue1 = keyRange.upper * 80; xValue2 = keyRange.upper * 102; QCPRange keyRange2 = m_customPlot->axisRect()->axis(QCPAxis::atLeft)->range(); yValue = keyRange2.lower; auto iter1 = m_customPlot->graph()->data()->findBegin(xValue1); xValue1 = iter1->mainKey(); auto iter2 = m_customPlot->graph()->data()->findBegin(xValue2); xValue2 = iter2->mainKey(); //左游标 QPen pen(Qt::red,1.5,Qt::SolidLine); //颜色 、宽度、样式(直线) m_lineLV = new QCPItemStraightLine(m_customPlot); m_lineLV->setLayer("overlay"); m_lineLV->setPen(pen);//设置游标线的样式 m_lineLV->setClipToAxisRect(true);//自适应范围 m_lineLV->point1->setCoords(xValue1, keyRange.upper);//起点坐标 ///m_lineLV->point2->setCoords(xValue1, 1);//终点坐标 m_lineLV->point2->setCoords(xValue1, 1);//终点坐标 m_lineLV->setVisible(false); //右游标 ///QPen penr(Qt::green,1.5,Qt::SolidLine); //颜色 、宽度、样式(直线) m_lineRV = new QCPItemStraightLine(m_customPlot); m_lineRV->setLayer("overlay"); m_lineRV->setPen(pen); m_lineRV->setClipToAxisRect(true); m_lineRV->point1->setCoords(xValue2, keyRange.lower); m_lineRV->point2->setCoords(xValue2, 1); m_lineRV->setVisible(false); //编辑框显示初始位置 m_lineEdit_left->setText(QString::number(m_lineLV->point1->key())); m_lineEdit_right->setText(QString::number(m_lineRV->point1->key())); m_customPlot->replot(); } catch (...) { qDebug("游标初始化异常!"); } } /******************* * @author xxx * @method * @param * 鼠标抓取事件 点击曲线游标显示 *******************/ void PlotWidget::mousePress(QMouseEvent *event) { try { QCPGraph *tmGraph = m_customPlot->graph(0); //得到锚点的像素坐标 QPointF temp = m_tracer->position->coords(); //将像素点转换成qcustomplot中的坐标值,并通过setGraphKey将锚点值设为真实数据值。 m_tracer->setGraphKey(m_customPlot->xAxis->pixelToCoord(event->pos().x())); //遍历曲线 for (int i = 0; i < m_customPlot->graphCount(); ++i) { //判断哪一条曲线被选中 if(m_customPlot->graph(i)->selected()) { //显示锚点 m_tracer->setVisible(true); tmGraph = m_customPlot->graph(i); //显示tip框 ///QToolTip::showText(event->globalPos(), tr( "

%L1

" ///QToolTip::showText(QCursor::pos(), tr( "

%L1

" QToolTip::showText(QCursor::pos(), tr("" "" "" "" "" "" "
X: %L1
,
Y: %L2
"). arg( QString::number( temp.x(), 'g' ) ) .arg( QString::number( temp.y(), 'g' ) ), this, this->rect()); break; } else { //没有曲线被选中,不显示锚点 m_tracer->setVisible(false); } } //将锚点设置到被选中的曲线上 m_tracer->setGraph(tmGraph); //重绘 m_customPlot->replot(); //定义鼠标距离游标的像素距离 double distanceLV = m_lineLV->selectTest(event->pos(), false); double distanceRV = m_lineRV->selectTest(event->pos(), false); ///double distanceH = m_lineH->selectTest(event->pos(), false); //定义游标标识,由上面的距离来决定移动那根游标 if (event->button() == Qt::RightButton && distanceLV <= 5 && m_customPlot->axisRect()->rect().contains(event->pos())){ lLineV = true; } if (event->button() == Qt::RightButton && distanceRV <= 5 && m_customPlot->axisRect()->rect().contains(event->pos())){ rLineV = true; } //左右游标重合时,先移动右游标(非必须) if(event->button() == Qt::RightButton){//鼠标右键判断 if(m_customPlot->axisRect()->rect().contains(event->pos())){//鼠标点在图像内 if(distanceLV <= 5 && distanceRV <= 5){//重合时 //这里获取曲线的最后一个值,以判断重合位置是否在末尾,如果是则先移动左游标,否则都先移动右游标 ///double end = tempXpoinLists[subscript].last(); double end = m_lineRV->point1->key(); double now = m_lineLV->point1->key(); if(now == end){ lLineV = true; rLineV = false; }else{ lLineV = false; rLineV = true; } } } } m_customPlot->replot(); } catch (...) { qDebug("系统发异常!"); } } /******************* * @author xxx * @method * @param * 游标移动 *******************/ void PlotWidget::mouseMove(QMouseEvent *event) { try{ //当前鼠标位置(像素坐标) double x_pos = event->pos().x(); ///double y_pos = event->pos().y(); //像素坐标转成实际的x,y轴的坐标 double x_val = m_customPlot->xAxis->pixelToCoord(x_pos); ///double y_val = m_customPlot->yAxis->pixelToCoord(y_pos); //获取当前曲线上最近的X轴点坐标 if(m_count_graph<=1) { auto iter = m_customPlot->graph(m_count_graph)->data()->findBegin(x_val); x_val = iter->mainKey(); } if(m_count_graph>1) { auto iter = m_customPlot->graph(1)->data()->findBegin(x_val); x_val = iter->mainKey(); } //获取当前游标X轴的坐标 double r_point = m_lineRV->point1->key(); double l_point = m_lineLV->point1->key(); //获取距离 double distanceLV = m_lineLV->selectTest(event->pos(), false); double distanceRV = m_lineRV->selectTest(event->pos(), false); //当鼠标在游标上时改变鼠标形状 if (distanceLV <= 5 || distanceRV <= 5){// || distanceH <= 5 && ui->plot->axisRect()->rect().contains(event->pos())){ m_customPlot->setCursor(Qt::ClosedHandCursor); }else{ m_customPlot->setCursor(Qt::ArrowCursor); } //游标移动判断 if(lLineV) {//移动左游标 if(x_val > r_point){ //跟右游标左判断,限制边界 m_lineLV->point1->setCoords(r_point, m_customPlot->yAxis->range().lower); m_lineLV->point2->setCoords(r_point, m_customPlot->yAxis->range().upper); }else { m_lineLV->point1->setCoords(x_val, m_customPlot->yAxis->range().lower); m_lineLV->point2->setCoords(x_val, m_customPlot->yAxis->range().upper); } m_lineEdit_left->setText(QString::number(m_lineLV->point1->key())); m_customPlot->replot(); } if(rLineV) { if (x_val < l_point) { m_lineRV->point1->setCoords(l_point, m_customPlot->yAxis->range().lower); m_lineRV->point2->setCoords(l_point, m_customPlot->yAxis->range().upper); } else { m_lineRV->point1->setCoords(x_val, m_customPlot->yAxis->range().lower); m_lineRV->point2->setCoords(x_val, m_customPlot->yAxis->range().upper); } m_lineEdit_right->setText(QString::number(m_lineRV->point1->key())); m_customPlot->replot(); } //进行相应的计算 if(lLineV || rLineV || bLineH){ // calculate_integral(); // calculate_average(); } } catch (...) { qDebug("系统发异常!"); } } /** * @brief Average::mouseRelease * @param e * 鼠标释放事件 关闭游标移动 */ void PlotWidget::mouseRelease() { lLineV = false; rLineV = false; bLineH = false; } void PlotWidget::get_coordinate_calcu() { mutex.lock(); if(slist_temper.size()!=slist_dsc.size()) return; QMap dd_map; QVector x(slist_temper.size()), y0(slist_dsc.size()); for(int i = 0; i < slist_temper.size(); ++i) { ///qDebug() << slist_temper.at(i).toDouble()<point1->key(); //左选线横轴坐标值 double x2 = m_lineRV->point1->key(); //右选线横轴坐标值 double y1 = dd_map.value(x1); double y2 = dd_map.value(x2); double k = (y2-y1)*1.0/(x2-x1); double b = y1-k*x1; //1、获取两游标当前的坐标点 int begin = 0, end = 0; double r_point = m_lineRV->point1->key(); double l_point = m_lineLV->point1->key(); //2、根据坐标点找到曲线中对应的数据点位置 begin是曲线中第一个点位置 end是最后一个点位置 for (int i = 0; i < x.length(); ++i) { if(x[i] == l_point){ begin = i; } if(x[i] == r_point){ end = i; break; } } int n = end-begin+1; QVector x_1(n), y_1(n); for (int i = 0; i < n; i++) { x_1[i] = x[begin+i]; y_1[i] = k*x[begin+i]+b; } QVariant dataVarx,dataVary; dataVarx.setValue(x_1); dataVary.setValue(y_1); emit send_line_data_to_plot(dataVarx,dataVary); //采用的是梯形计算法,也可以采用积分等面积算法进行计算 //根据这两个点位置区间计算所有的形成梯形面积 面积公式:(上底 + 下底)* 高 / 2; double upper; //上底 double lower; //下底 double high; //高 double area = 0; //面积 for (int i = begin; i < end; ++i) { upper = k*x[i]+b-y0[i]; lower = k*x[i+1]+b-y0[i+1]; high = x[i+1] - x[i]; area += (upper+ lower)*high / 2; } qDebug() << "caculate area"<< area < qm_kb; double k1; double b1; double kmin = 0.0; double kmax = -10000.0; double b_tang1 = 0.0; int tangp1 = 0, tangp2 = 0; for (int j = begin+4; j < middle-4; j++) { k1= (y0[j+4]-y0[j-4])/(x[j+4]-x[j-4]); b1 =y0[j]-k1*x[j]; if(k1 < kmin) { kmin = k1; tangp1 = j; b_tang1 = b1; } } g_kmin = kmin; g_b_tang1 = b_tang1; ///emit show_tang(); QString expression1 = QString("y=%1 * x + %2").arg(kmin).arg(b_tang1); qDebug()<<"切线表达式1: "<point1->key(); double y_tang_2 = kmin*x_tang_2+b_tang1; double x_conn_3 = m_lineLV->point1->key(); //左选线横轴坐标值 double y_conn_3 = dd_map.value(x1); double x_conn_4 = m_lineRV->point1->key(); //右选线横轴坐标值 double y_conn_4 = dd_map.value(x2); ///Point p1,p2,p3,p4;对应的四个点,根据实际应用场景赋值 double a1, a2, a3, c1, c2, c3; double t, target_x, target_y; a1 = y_conn_4 - y_conn_3; a2 = y_conn_3 - y_tang_1; a3 = y_tang_2 - y_tang_1; c1 = x_conn_4 - x_conn_3; c2 = x_conn_3 - x_tang_1; c3 = x_tang_2 - x_tang_1; t = (a3 * c2 - a2 * c3) / (a1 * c3 - a3 * c1); target_x = (x_conn_4 - x_conn_3) * t + x_conn_3; target_y = (y_conn_4- y_conn_3) * t + y_conn_3; g_target_x1 = target_x; g_target_y1 = target_y; qDebug()<<"两直线交点坐标1: "< kmax) { kmax = k2; tangp2 = t; b_tang2 = b2; } } g_kmax = kmax; g_b_tang2 = b_tang2; double x_tang_11 = x[tangp2]; double y_tang_11 = y0[tangp2]; double x_tang_22 = m_lineRV->point1->key(); double y_tang_22 = kmax*x_tang_22+b_tang2; double x_conn_33 = m_lineLV->point1->key(); //左选线横轴坐标值 double y_conn_33 = dd_map.value(x1); double x_conn_44 = m_lineRV->point1->key(); //右选线横轴坐标值 double y_conn_44 = dd_map.value(x2); ///Point p1,p2,p3,p4;对应的四个点,根据实际应用场景赋值 double a11, a22, a33, c11, c22, c33; double t2, target_x2, target_y2; a11 = y_conn_44 - y_conn_33; a22 = y_conn_33 - y_tang_11; a33 = y_tang_22 - y_tang_11; c11 = x_conn_44 - x_conn_33; c22 = x_conn_33 - x_tang_11; c33 = x_tang_22 - x_tang_11; t2 = (a33 * c22 - a22 * c33) / (a11 * c33 - a33 * c11); target_x2 = (x_conn_44 - x_conn_33) * t2 + x_conn_33; target_y2 = (y_conn_44- y_conn_33) * t2 + y_conn_33; g_target_x2 = target_x2; g_target_y2 = target_y2; qDebug()<<"两直线交点坐标2: "<