#include #include #include #include #include #include #include #include "QtConcurrent/qtconcurrentrun.h" #include "manager.h" enum Group {CM, PM, CN, PN}; static const bool multipleThreads = true; static const int nThreads = 4; static const bool blackAndWhite = false; /* * Конструктор */ Manager::Manager(QObject *parent) : manItem(0), xCoord(100, 0), yCoord(100, 0), cowardMedian(0), cowardNormal(0), protectorMedian(0), protectorNormal(0), agentRadius(0), speedDistr(0), gamerSpeed(0), period(0), initDistr(0), enmity(0), newEnmity(0), viewOrPackageMode(0), nIterations(1), nModels(1), outputToTxt(false), typeContentment(0), radiusLocality(0), QObject(parent) { window = new QWidget; base = new QGridLayout; QGroupBox *settings = new QGroupBox; initSettings(settings); tabWindow = new QTabWidget; initTab(tabWindow); base->addWidget(settings, 0, 1); base->addWidget(tabWindow, 0, 0); window->setLayout(base); window->setWindowTitle("Agressor-Protector"); window->show(); // создание таймера timer = new QTimer(this); timer->setInterval(1000/10); timer->stop(); // хранитель данных history = new APHistory(); // ToDo: setNModel } /* * Создание окна настроек */ void Manager::initSettings(QGroupBox *set){ QVBoxLayout *box = new QVBoxLayout; QGroupBox *box1 = new QGroupBox; QGroupBox *box2 = new QGroupBox; QGroupBox *box3 = new QGroupBox; QGroupBox *box4 = new QGroupBox; QGroupBox *box5 = new QGroupBox; QGridLayout *hbox1 = new QGridLayout; QGridLayout *hbox2 = new QGridLayout; QGridLayout *hbox3 = new QGridLayout; QGridLayout *hbox4 = new QGridLayout; QVBoxLayout *hbox5 = new QVBoxLayout; QLabel *labelMode1 = new QLabel("Gamer is a coward"); QLabel *labelMode2 = new QLabel("Gamer is a protector"); QLabel *labelStrategy1 = new QLabel("Along median"); QLabel *labelStrategy2 = new QLabel("Along normal"); QSpinBox *spinCM = new QSpinBox; spinCM->setMaximum(1000); connect (spinCM, SIGNAL(valueChanged(int)), this, SLOT(setCowardMedian(int))); QSpinBox *spinCN = new QSpinBox; spinCN->setMaximum(1000); connect (spinCN, SIGNAL(valueChanged(int)), this, SLOT(setCowardNormal(int))); QSpinBox *spinPM = new QSpinBox; spinPM->setMaximum(1000); connect (spinPM, SIGNAL(valueChanged(int)), this, SLOT(setProtectorMedian(int))); QSpinBox *spinPN = new QSpinBox; spinPN->setMaximum(1000); connect (spinPN, SIGNAL(valueChanged(int)), this, SLOT(setProtectorNormal(int))); QLabel *labelRadius = new QLabel("Gamer radius:"); QSpinBox *boxRadius = new QSpinBox; connect(boxRadius, SIGNAL(valueChanged(int)), this, SLOT(setAgentRadius(int))); QLabel *labelEnmity = new QLabel("Enmity:"); QSpinBox *spinBoxEnmity = new QSpinBox; connect(spinBoxEnmity, SIGNAL(valueChanged(int)), this, SLOT(setNewEnmity(int))); // QLabel *labelSpeedDistr = new QLabel("Speed distribution:"); // QComboBox *comboSpeedDistr = new QComboBox; // comboSpeedDistr->addItem("homogeneous"); QLabel *labelSpeed = new QLabel("Gamer speed:"); QSpinBox *spinSpeed = new QSpinBox; spinSpeed->setMaximum(10); connect(spinSpeed, SIGNAL(valueChanged(int)), this, SLOT(setGamerSpeed(int))); QLabel *labelCont = new QLabel("Type of contenment calculation: "); QComboBox *comboContent = new QComboBox; comboContent->addItem("absolute"); comboContent->addItem("comparative"); connect(comboContent, SIGNAL(currentIndexChanged(int)), this, SLOT(setTypeContenment(int))); QLabel *labelLocality = new QLabel("Radius of locality"); spinLocality = new QSpinBox; spinLocality->setEnabled(false); connect(spinLocality, SIGNAL(valueChanged(int)), this, SLOT(setRadiusLocality(int))); connect(comboContent, SIGNAL(currentIndexChanged(int)), this, SLOT(manageSpinLocality(int))); QCheckBox *checkPeriod = new QCheckBox; checkPeriod->setText("Periodicity"); connect(checkPeriod, SIGNAL(toggled(bool)), this, SLOT(setPeriodicity(bool))); QLabel *label = new QLabel("Initial distribution:"); QComboBox *comboDistr = new QComboBox; comboDistr->addItem("random"); comboDistr->addItem("on the circle"); connect(comboDistr, SIGNAL(currentIndexChanged(int)), this, SLOT(setDistr(int))); createButton = new QPushButton; createButton->setText("Create"); connect(createButton, SIGNAL(clicked()), this, SLOT(resetProgressBarAndHistory())); connect(createButton, SIGNAL(clicked()), this, SLOT(initModel())); QLabel *labelViewOrPackage = new QLabel("Type of job: "); viewOrPackage = new QComboBox; viewOrPackage->addItem("one model in detail"); viewOrPackage->addItem("processing"); connect(viewOrPackage, SIGNAL(currentIndexChanged(int)), this, SLOT(setviewOrPackageMode(int))); connect(viewOrPackage, SIGNAL(currentIndexChanged(int)), this, SLOT(managePackageOptions(int))); checkLink = new QCheckBox; checkLink->setText("Show links"); checkOutputToTxt = new QCheckBox; checkOutputToTxt->setText("Output to txt"); connect(checkOutputToTxt, SIGNAL(toggled(bool)), this, SLOT(setOutputToTxt(bool))); QLabel *label3 = new QLabel("Updating frequency: "); comboTime = new QComboBox; comboTime->addItem("1000/10"); comboTime->addItem("1000/20"); comboTime->addItem("1000/30"); comboTime->addItem("1000/50"); comboTime->addItem("1000/100"); connect(comboTime, SIGNAL(currentIndexChanged(int)), this, SLOT(timerRestart(int))); QLabel *labelIterations = new QLabel("Number of iterations: "); spinIterations = new QSpinBox; spinIterations->setMinimum(1); spinIterations->setMaximum(10000); spinIterations->setEnabled(false); connect(spinIterations, SIGNAL(valueChanged(int)), this, SLOT(setNIterations(int))); QLabel *labelModels = new QLabel("Number of models: "); spinModels = new QSpinBox; spinModels->setMinimum(1); spinModels->setMaximum(1000); spinModels->setEnabled(false); connect(spinModels, SIGNAL(valueChanged(int)), this, SLOT(setNModels(int))); buttonTime = new QPushButton; buttonTime->setText("Start"); connect(buttonTime, SIGNAL(clicked()), this, SLOT(handleButton())); buttonTime->setEnabled(false); hbox1->addWidget(labelMode1, 0, 1); hbox1->addWidget(labelMode2, 0, 2); hbox1->addWidget(labelStrategy1, 1, 0); hbox1->addWidget(labelStrategy2, 2, 0); hbox1->addWidget(spinCM, 1, 1); hbox1->addWidget(spinCN, 2, 1); hbox1->addWidget(spinPM, 1, 2); hbox1->addWidget(spinPN, 2, 2); box1->setLayout(hbox1); box1->setTitle("Gamers number"); hbox2->addWidget(labelRadius, 0, 0); hbox2->addWidget(boxRadius, 0, 1); hbox2->addWidget(labelEnmity, 1, 0); hbox2->addWidget(spinBoxEnmity, 1, 1); // hbox2->addWidget(labelSpeedDistr, 2, 0); // hbox2->addWidget(comboSpeedDistr, 2, 1); hbox2->addWidget(labelSpeed, 3, 0); hbox2->addWidget(spinSpeed, 3, 1); hbox2->addWidget(labelCont, 4, 0); hbox2->addWidget(comboContent, 4, 1); hbox2->addWidget(labelLocality, 5, 0); hbox2->addWidget(spinLocality, 5, 1); box2->setLayout(hbox2); box2->setTitle("Gamer settings"); hbox3->addWidget(checkPeriod, 0, 0); hbox3->addWidget(label, 1, 0); hbox3->addWidget(comboDistr, 1, 1); box3->setLayout(hbox3); box3->setTitle("Scene settings"); hbox4->addWidget(labelViewOrPackage, 0, 0); hbox4->addWidget(viewOrPackage, 0, 1); hbox4->addWidget(checkLink, 1, 0); hbox4->addWidget(checkOutputToTxt, 1, 1); hbox4->addWidget(label3, 2, 0); hbox4->addWidget(comboTime, 2, 1); hbox4->addWidget(labelIterations, 3, 0); hbox4->addWidget(spinIterations, 3, 1); hbox4->addWidget(labelModels, 4, 0); hbox4->addWidget(spinModels, 4, 1); box4->setLayout(hbox4); hbox5->addWidget(createButton); hbox5->addWidget(buttonTime); box5->setLayout(hbox5); box->addWidget(box1); box->addWidget(box2); box->addWidget(box3); box->addWidget(box4); box->addWidget(box5); box->addStretch(); set->setLayout(box); } void Manager::initTab(QTabWidget *tabs){ // Первая вкладка - визуализация одной модели (сцена + график) QWidget *viewTab = new QWidget; QGridLayout *viewLayout = new QGridLayout; // Создание и заполнение сцены scene = new QGraphicsScene; scene->setSceneRect(-300, -300, 600, 600); scene->setItemIndexMethod(QGraphicsScene::NoIndex); QGraphicsView *view = new QGraphicsView(scene); view->setRenderHint(QPainter::Antialiasing); view->setCacheMode(QGraphicsView::CacheBackground); view->resize(800, 800); view->setMinimumWidth(600); view->show(); // Создание графика ср.неудовлетворённости QLabel *labelGraph = new QLabel("Dynamics of average contenment"); labelContent = new QLabel("Average contentment: "); plot = new QCustomPlot; plot->addGraph(); for (int i = 0; i < 100; i++) { xCoord[i] = i; } plot->graph(0)->setData(xCoord, yCoord); plot->yAxis->setRange(0, 1); plot->graph(0)->rescaleAxes(); plot->yAxis->setVisible(false); plot->xAxis->setTickLabels(false); viewLayout->addWidget(view, 0, 0, 1, 2); viewLayout->addWidget(labelGraph, 1, 0); viewLayout->addWidget(labelContent, 1, 1); viewLayout->addWidget(plot, 2, 0, 1, 2); viewTab->setLayout(viewLayout); // Вторая вкладка - пакетное задание (прогресс-бар) QWidget *packageTab = new QWidget; QGridLayout *packageLayout = new QGridLayout; prBar = new QProgressBar; prBar->setValue(0); QLabel *graphComboLabel = new QLabel("Compose the graphic for: "); graphCombo = new QComboBox; graphCombo->setEnabled(false); graphCombo->addItem("---"); connect(graphCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(composeGraph(int))); batchPlot = new QCustomPlot; batchPlot->addGraph(); batchPlot->addGraph(); batchPlot->addGraph(); batchPlot->addGraph(); batchPlot->addGraph(); batchPlot->graph(0)->setPen(QPen(Qt::black, 2)); if (blackAndWhite) { batchPlot->graph(CM + 1)->setPen(QPen(Qt::SolidLine)); batchPlot->graph(PM + 1)->setPen(QPen(Qt::DashDotLine)); batchPlot->graph(CN + 1)->setPen(QPen(Qt::DashLine)); QPen * pen = new QPen(QPen(Qt::DashDotDotLine)); pen->setWidth(2); batchPlot->graph(PN + 1)->setPen(*pen); } else { batchPlot->graph(CM + 1)->setPen(QPen(Qt::red)); batchPlot->graph(PM + 1)->setPen(QPen(Qt::yellow)); batchPlot->graph(CN + 1)->setPen(QPen(Qt::darkBlue)); batchPlot->graph(PN + 1)->setPen(QPen(Qt::cyan)); } batchPlot->graph(0)->setName("Average for all agents"); batchPlot->graph(CM + 1)->setName("Average for coward-median"); batchPlot->graph(PM + 1)->setName("Average for all protector-median"); batchPlot->graph(CN + 1)->setName("Average for all coward-normal"); batchPlot->graph(PN + 1)->setName("Average for all protector-normal"); xBatchCoord.resize(100); yBatchCoord.resize(100); yBatchCoord.fill(0); for (int i = 0; i < 100; i++) { xBatchCoord[i] = i; } batchPlot->graph(0)->setData(xBatchCoord, yBatchCoord); batchPlot->yAxis->setRange(0, 1.05); QVector ticks; qreal i = 0; while (i <= 1.05) { ticks << i; i += 0.1; } batchPlot->yAxis->setAutoTicks(false); batchPlot->yAxis->setTickVector(ticks); batchPlot->graph(0)->rescaleAxes(); QLabel *labelSaveWithName = new QLabel("Save with name: "); lineSaveWithName = new QLineEdit; lineSaveWithName->setPlaceholderText("For example: default_name"); QPushButton *buttonSaveGraph = new QPushButton; buttonSaveGraph->setText("Save as jpeg"); connect(buttonSaveGraph, SIGNAL(clicked()), this, SLOT(saveGragh())); packageLayout->addWidget(prBar, 0, 0, 1, 2); packageLayout->addWidget(graphComboLabel, 1, 0, 1, 1); packageLayout->addWidget(graphCombo, 1, 1, 1, 1); packageLayout->addWidget(batchPlot, 2, 0, 2, 2); packageLayout->addWidget(labelSaveWithName, 4, 0, 1, 1); packageLayout->addWidget(lineSaveWithName, 4, 1, 1, 1); packageLayout->addWidget(buttonSaveGraph, 5, 1, 1, 1); packageTab->setLayout(packageLayout); tabs->addTab(viewTab, "One model in detail"); tabs->addTab(packageTab, "Batch processing"); connect(tabs, SIGNAL(currentChanged(int)), viewOrPackage, SLOT(setCurrentIndex(int))); } QVector Manager::calculateAvContenmentForGroups(uint typeCalc, uint iModel){ qreal max = 0; qreal res = 0; QVector cont(4, 0); QList neibours; QVector nAgents; nAgents << cowardMedian << protectorMedian << cowardNormal << protectorNormal; if (modelList[iModel]->getAgentList().size() == 0){ return cont; } // С оглядкой на всех агентов else if (typeCalc == 0){ int ind = 0; for (int i = 0; i < modelList[iModel]->getAgentList().size(); i++){ if (modelList[iModel]->getAgentList()[i]->getMode() == 0) { ind = modelList[iModel]->getAgentList()[i]->getStrategy() == 0 ? 0 : 2; } else { ind = modelList[iModel]->getAgentList()[i]->getStrategy() == 0 ? 1 : 3; } if (modelList[iModel]->getAgentList()[i]->getDistTarget() > max){ max = modelList[iModel]->getAgentList()[i]->getDistTarget(); } else{} if (max > 0.0) { modelList[iModel]->getAgentList()[i]->setContentment(modelList[iModel]->getAgentList()[i]->getDistTarget()/max); cont[ind] += modelList[iModel]->getAgentList()[i]->getDistTarget()/max; } else{ modelList[iModel]->getAgentList()[i]->setContentment(1); cont[ind] += 1; } } } // С оглядкой на агентов внутри окрестности else if (typeCalc == 1){ for (int i = 0; i < modelList[iModel]->getAgentList().size(); i++){ int ind = 0; if (modelList[iModel]->getAgentList()[i]->getMode() == 0) { ind = modelList[iModel]->getAgentList()[i]->getStrategy() == 0 ? 0 : 2; } else { ind = modelList[iModel]->getAgentList()[i]->getStrategy() == 0 ? 1 : 3; } neibours = modelList[iModel]->DangerGamer(i, 0, 0, radiusLocality); max = modelList[iModel]->getAgentList()[i]->getDistTarget(); for (int j = 0; j < neibours.size(); j++){ if (neibours[j]->getDistTarget() > max){ max = neibours[j]->getDistTarget(); } else{} } if (max > 0.0) { modelList[iModel]->getAgentList()[i]->setContentment(modelList[iModel]->getAgentList()[i]->getDistTarget()/max); cont[ind] += modelList[iModel]->getAgentList()[i]->getDistTarget()/max; } else{ modelList[iModel]->getAgentList()[i]->setContentment(1); cont[ind] += 1; } } } for (int i = CM; i < PN + 1; i++){ if (nAgents[i] != 0) { res += cont[i]; cont[i] = cont[i]/nAgents[i]; } } modelList[iModel]->setAvContentment(res/modelList[iModel]->getAgentList().size()); yCoord.removeFirst(); yCoord.push_back(res/modelList[iModel]->getAgentList().size()); return cont; } /* * Создание модели по полученным данным */ void Manager::initModel(){ buttonTime->setText("Start"); createButton->setText("Recreate"); yCoord.fill(0); graphCombo->setCurrentIndex(0); graphCombo->setEnabled(false); // Визуализация одной модели if (viewOrPackageMode == 0){ timer->stop(); history->addClassHistory(); history->addClassGroupHistory(); Model *model = new Model(0, cowardMedian, cowardNormal, protectorMedian, protectorNormal, agentRadius, gamerSpeed, period, initDistr, enmity, newEnmity); modelList.push_back(model); if (manItem != 0){ delete manItem; } batchPlot->clearItems(); batchPlot->replot(); // Создание управленца визуализацией manItem = new ManagerItem(model->getAgentList(), scene, cowardMedian, cowardNormal, protectorMedian); connect(timer, SIGNAL(timeout()), this, SLOT(timerEvent())); connect(timer, SIGNAL(timeout()), manItem, SLOT(gameEvent())); connect(checkLink, SIGNAL(toggled(bool)), manItem, SLOT(setLink(bool))); } // Пакетное задание else { // Очистка сцены и графика на первой вкладке scene->clear(); plot->graph(0)->setData(xCoord, yCoord); plot->replot(); prBar->setMinimum(0); prBar->setMaximum(nIterations*nModels); } setEnmity(newEnmity); buttonTime->setEnabled(true); } /* * Событие игры. Вычисление новых координат для всех игроков на сцене */ void Manager::timerEvent(){ modelList[0]->modelIteration(); history->addGroupAvContenmentData(0, calculateAvContenmentForGroups(typeContentment, 0)); history->addAvContenmentData(0, modelList[0]->getAvContentment()); if (outputToTxt) { history->postPrintModelData(0); history->postPrintGroupData(0); } plot->graph(0)->setData(xCoord, yCoord); plot->replot(); history->addGroupAvContenmentData(0, calculateAvContenmentForGroups(typeContentment, 0)); history->addAvContenmentData(0, modelList[0]->getAvContentment()); // запись в хранитель данных labelContent->setText("Average contenment: " + QString::number(modelList[0]->getAvContentment())); } void Manager::iteration(uint j) { Model *model = new Model(j, cowardMedian, cowardNormal, protectorMedian, protectorNormal, agentRadius, gamerSpeed, period, initDistr, enmity, newEnmity); modelList.append(model); for(int i = 0; i < nIterations; i++){ model->modelIteration(); history->addGroupAvContenmentData(modelList.indexOf(model), calculateAvContenmentForGroups(typeContentment, modelList.indexOf(model))); history->addAvContenmentData(modelList.indexOf(model), model->getAvContentment()); //qApp->processEvents(); } if (outputToTxt) { history->postPrintModelData(modelList.indexOf(model)); history->postPrintGroupData(modelList.indexOf(model)); } model->clear(); //delete model; } void Manager::handlePrBar() { //prBar->setValue(prBar->value() + nIterations); std::cout << "handlePrBar" << std::endl; } /* * Остановка/возобновление игры */ void Manager::handleButton(){ // Визуализация модели if(viewOrPackageMode == 0){ if (timer->isActive()){ timer->stop(); buttonTime->setText("Start"); } else { timer->start(timer->interval()); buttonTime->setText("Pause"); } } // Пакетное задание (без возможности остановки) else{ buttonTime->setText("In process..."); buttonTime->setEnabled(false); createButton->setEnabled(false); tabWindow->setTabEnabled(0, false); //prBar->setValue(0); if(!multipleThreads){ for (int i = 0; i < nModels; i++) { history->addClassHistory(); history->addClassGroupHistory(); iteration(i); prBar->setValue(prBar->value() + nIterations); } } else { QVector > futureVector; QVector *> watcherVector; for (int i = 0; i < nThreads; i++) { QFuture future; futureVector.append(future); QFutureWatcher *watcher = new QFutureWatcher; watcherVector.append(watcher); //connect(watcherVector[i], SIGNAL(finished()), this, SLOT(handlePrBar())); } for(int i = 0; i < nModels; i++) { history->addClassHistory(); history->addClassGroupHistory(); } for(int j = 0; j < nModels/nThreads; j++){ for (int i = 0; i < nThreads; i++) { //qApp->processEvents(); futureVector[i] = QtConcurrent::run(this, &Manager::iteration, j*nThreads + i); watcherVector[i]->setFuture(futureVector[i]); } qApp->processEvents(); prBar->setValue(prBar->value() + nThreads*nIterations); for (int i = 0; i < nThreads; i++) { watcherVector[i]->waitForFinished(); //modelList[j*nThreads + i]->clear(); //prBar->setValue(prBar->value() + nIterations); } } //qApp->processEvents(); if (nModels % nThreads != 0) { for (int i = 0; i < nModels % nThreads; i++) { futureVector[i] = QtConcurrent::run(this, &Manager::iteration, nThreads*(nModels/nThreads) + i); watcherVector[i]->setFuture(futureVector[i]); } prBar->setValue(prBar->value() + (nModels % nThreads)*nIterations); for (int i = 0; i < nModels % nThreads; i++) { watcherVector[i]->waitForFinished(); //modelList[nThreads*(nModels/nThreads) + i]->clear(); //prBar->setValue(prBar->value() + nIterations); } } } qDeleteAll(modelList.begin(), modelList.end()); modelList.clear(); if (outputToTxt) { history->postPrintGlobalAverage(); } disconnect(graphCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(composeGraph(int))); graphCombo->clear(); graphCombo->addItem("---"); for(int i = 0; i < nModels; i++){ QString comboString = "Model "; comboString += QString::number(i + 1); graphCombo->addItem(comboString); } if (nModels > 1) { graphCombo->addItem("Average for all models"); } connect(graphCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(composeGraph(int))); buttonTime->setText("Start"); buttonTime->setEnabled(true); graphCombo->setEnabled(true); createButton->setEnabled(true); tabWindow->setTabEnabled(0, true); } } /* * Перезапуск таймера */ void Manager::timerRestart(int index){ if (index == 0){ timer->setInterval(1000/10); } else if(index == 1){ timer->setInterval(1000/20); } else if(index == 2){ timer->setInterval(1000/30); } else if(index == 3){ timer->setInterval(1000/50); } else if (index == 4){ timer->setInterval(1000/100); } else{} } void Manager::resetProgressBarAndHistory(){ prBar->setValue(0); history->clearHistory(); } /* * Вкл/выкл спинбокс для радиуса окрестности */ void Manager::manageSpinLocality(int value){ if (value == 0){ spinLocality->setEnabled(false); } else{ spinLocality->setEnabled(true); } } /* * Вкл/выкл спинбокс для числа итераций и спинбокс для числа запусков модели */ void Manager::managePackageOptions(int val){ if(val == 0){ spinIterations->setEnabled(false); spinModels->setEnabled(false); checkLink->setEnabled(true); comboTime->setEnabled(true); } else { timer->stop(); spinIterations->setEnabled(true); spinModels->setEnabled(true); checkLink->setEnabled(false); comboTime->setEnabled(false); } tabWindow->setCurrentIndex(val); } void Manager::composeGraph(int iModel) { xBatchCoord.resize(nIterations); QVector avCM(nIterations, 0); QVector avPM(nIterations, 0); QVector avCN(nIterations, 0); QVector avPN(nIterations, 0); for(int i = 0; i < nIterations; i++) { xBatchCoord[i] = i; } yBatchCoord.resize(nIterations); batchPlot->xAxis->setRange(0, nIterations + 1); if(iModel == 0) { yBatchCoord.fill(0); } else if (iModel == nModels + 1){ yBatchCoord = history->getAverageForAllModels().toVector(); avCM = history->getAverageForGroup(CM).toVector(); avPM = history->getAverageForGroup(PM).toVector(); avCN = history->getAverageForGroup(CN).toVector(); avPN = history->getAverageForGroup(PN).toVector(); } else { yBatchCoord = history->getHistory(iModel - 1).toVector(); avCM = history->getGroupHistory(iModel - 1, CM).toVector(); avPM = history->getGroupHistory(iModel - 1, PM).toVector(); avCN = history->getGroupHistory(iModel - 1, CN).toVector(); avPN = history->getGroupHistory(iModel - 1, PN).toVector(); } batchPlot->graph(0)->setData(xBatchCoord, yBatchCoord); batchPlot->graph(CM + 1)->setData(xBatchCoord, avCM); batchPlot->graph(PM + 1)->setData(xBatchCoord, avPM); batchPlot->graph(CN + 1)->setData(xBatchCoord, avCN); batchPlot->graph(PN + 1)->setData(xBatchCoord, avPN); batchPlot->legend->setVisible(true); batchPlot->replot(); } void Manager::saveGragh() { batchPlot->saveJpg(lineSaveWithName->text() + ".jpg"); }