#include "result.h" #include "gnuplot-iostream.h" #include "ui_result.h" #include #include #include #include #include #include // setprecision #include #include #include #include #include #include #define SHELL 1 #define DEA 2 using std::cout; using std::endl; using std::string; using std::vector; Result::Result(std::shared_ptr db, int rennid, QWidget * parent) : QWidget(parent), ui(new Ui::Result) { ui->setupUi(this); this->db = db; // prepare dummy data vector header; // dummy for now // this->rennid = 39; this->rennid = rennid; // test data header.push_back("Spalte 1"); header.push_back("Spalte 2"); vector> data; vector subData; subData.push_back(1); subData.push_back(2); data.push_back(subData); data.push_back(subData); this->ui->tWResult->resizeColumnsToContents(); this->ui->tWResult->horizontalHeader()->setStretchLastSection(true); this->ui->tWResult->verticalHeader()->setVisible(true); // this->model->setHeaderData(0, Qt::Horizontal, "Test"); // connects // this->ui->pbClose->clicked() std::stringstream statement; statement << "select date from rennen where id like " << boost::lexical_cast(rennid); try { this->renndatum = this->db->getData2(statement.str(), 1).at(0).at(0); this->setWindowTitle(renndatum); } catch (std::exception & e) { Q_UNUSED(e); cout << "Renndatum konnt aus Datenbank nicht gelesen werden" << endl; } // clear stringstream statement.str(std::string()); statement << "select minimumroundtime from rennen where id like " << boost::lexical_cast(rennid); try { this->minimumTime = this->db->getData2(statement.str(), 1).at(0).at(0).toInt(); } catch (std::exception & e) { Q_UNUSED(e); cout << "Minimalzeit pro Runde konnte aus Datenbank nicht gelesen " "werden." << endl; } vector Fahrernamen; for (size_t i = 0; i < this->getFahrerIds(this->rennid).size(); i++) { Fahrernamen.push_back( this->getFahrerName(this->getFahrerIds(this->rennid).at(i))); } vector AutoIds = this->getAutoIds(this->rennid); this->ui->tWResult->setRowCount(static_cast(AutoIds.size()) * 2 + 4); this->ui->tWResult->setColumnCount(static_cast(Fahrernamen.size()) + 4); int row = 0; int col = 0; this->ui->tWResult->setItem(row, col, new QTableWidgetItem("Auto")); row += 0; col += 1; this->ui->tWResult->setItem(row, col, new QTableWidgetItem("Bahn")); col += 1; for (string fahrername : Fahrernamen) { this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString(fahrername))); col += 1; } this->ui->tWResult->setItem(row, col, new QTableWidgetItem("Durchschnitt Auto")); col += 1; this->ui->tWResult->setItem( row, col, new QTableWidgetItem("Durchschnitt Auto gesamt")); this->ui->tWResult->resizeColumnsToContents(); row = 1; col = 1; for (size_t i = 0; i <= AutoIds.size(); i++) { this->ui->tWResult->setItem(row, col, new QTableWidgetItem("Shell")); row += 1; this->ui->tWResult->setItem(row, col, new QTableWidgetItem("Dea")); row += 1; } vector AutoNamen; for (size_t i = 0; i < AutoIds.size(); i++) { AutoNamen.push_back(this->getAutoName(AutoIds.at(i))); } col = 0; row = 1; for (string autoname : AutoNamen) { this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString(autoname))); row += 2; } this->ui->tWResult->setItem(row, col, new QTableWidgetItem("Durchschnitt Person")); row += 2; this->ui->tWResult->setItem( row, col, new QTableWidgetItem("Durchschnitt Person ges")); row = 1; col = 2; vector> zeiten; vector subZeiten; for (int fahrer : this->getFahrerIds(this->rennid)) { for (int car : this->getAutoIds(this->rennid)) { int shellmin = this->getMinimum(fahrer, SHELL, this->rennid, car, this->minimumTime); int deamin = this->getMinimum(fahrer, DEA, this->rennid, car, this->minimumTime); subZeiten.push_back(static_cast(shellmin) / 1000); subZeiten.push_back(static_cast(deamin) / 1000); this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(static_cast(shellmin) / 1000, 3)))); row += 1; this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(static_cast(deamin) / 1000, 3)))); row += 1; } zeiten.push_back(subZeiten); subZeiten.clear(); col += 1; row = 1; } // Durchschnitt Fahrer Shell und Dea row = static_cast(AutoNamen.size()) * 2 + 1; col = 2; for (size_t i = 0; i < Fahrernamen.size(); i++) { vector shellListe; vector dealiste; for (size_t k = 0; k < zeiten.at(i).size(); k++) { if (k % 2 == 0) { shellListe.push_back(zeiten.at(i).at(k)); } else { dealiste.push_back(zeiten.at(i).at(k)); } } this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(this->meanVal(shellListe), 3)))); row += 1; this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(this->meanVal(dealiste), 3)))); row -= 1; col += 1; shellListe.clear(); dealiste.clear(); } // Durchschnitt Auto Shell und Dea col = static_cast(Fahrernamen.size()) + 2; row = 1; vector durschnittAuto; for (size_t i = 0; i < AutoIds.size() * 2; i++) { //*2 weil 2 Bahnen for (size_t k = 0; k < Fahrernamen.size(); k++) { durschnittAuto.push_back(zeiten.at(k).at(i)); } this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(this->meanVal(durschnittAuto), 3)))); row += 1; durschnittAuto.clear(); } // Durchschnitt Fahrer ges row = static_cast(AutoIds.size()) * 2 + 3; col = 2; for (size_t i = 0; i < Fahrernamen.size(); i++) { this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(this->meanVal(zeiten.at(i)), 3)))); col += 1; } // Durchschnitt Auto ges col = static_cast(Fahrernamen.size()) + 3; row = 1; for (size_t i = 0; i < AutoIds.size() * 2; i++) { //*2 weil 2 Bahnen if (i % 2 == 0) { vector durschnittAuto; for (size_t k = 0; k < Fahrernamen.size(); k++) { durschnittAuto.push_back(zeiten.at(k).at(i)); durschnittAuto.push_back(zeiten.at(k).at(i + 1)); } this->ui->tWResult->setItem( row, col, new QTableWidgetItem(QString::fromStdString( this->myRound(this->meanVal(durschnittAuto), 3)))); row += 2; durschnittAuto.clear(); } } // Minimum durchschnitt markieren row = static_cast(AutoIds.size()) * 2 + 3; col = 2; vector avgList; for (size_t i = 0; i < Fahrernamen.size(); i++) { QString value = this->ui->tWResult->item(row, col)->text(); avgList.push_back(value.toFloat()); col += 1; } row = static_cast(AutoIds.size()) * 2 + 3; col = 2; for (size_t i = 0; i < Fahrernamen.size(); i++) { if (this->myMin(avgList) == this->ui->tWResult->item(row, col)->text().toFloat()) { this->ui->tWResult->item(row, col)->setBackground( QColor(118, 238, 0)); } col += 1; } // minimum abs markieren // minimum finden vector temp; for (size_t i = 0; i < zeiten.size(); i++) { temp.push_back(this->myMin(zeiten.at(i))); } float minimum = this->myMin(temp); col = 2; row = 1; for (size_t i = 0; i < Fahrernamen.size(); i++) { for (size_t k = 0; k < AutoIds.size() * 2; k++) { // self.tWRennergebnis.item(row + k, col + // i).setBackground(QtGui.QColor(255, 215, 0)) if (this->ui->tWResult->item(row + k, col + i)->text().toFloat() == minimum) { this->ui->tWResult ->item(row + static_cast(k), col + static_cast(i)) ->setBackground(QColor(255, 215, 0)); } } } this->ui->tWResult->resizeColumnsToContents(); this->ui->tWResult->horizontalHeader()->setStretchLastSection(true); this->drawPlots(rennid); } void Result::drawPlots(int rennid) { // get drivers vector driverIds = this->getFahrerIds(rennid); vector drivers; for_each(driverIds.begin(), driverIds.end(), [&drivers, this](int id) { drivers.push_back(this->getFahrerName(id)); }); vector carIds = this->getAutoIds(rennid); // get minimal time from race std::stringstream statement; statement << "select rennen.minimumRoundtime from Rennen where id like " << boost::lexical_cast(rennid); int minTimeRace = 2950; try { minTimeRace = this->db->getData2(statement.str(), 1).at(0).at(0).toInt(); } catch (std::exception & e) { Q_UNUSED(e); cout << "minimal race time not readable from database" << endl; cout << "min time set to: " << minTimeRace; } vector times; struct Times tempTimes; int sumShell = 0; int sumDea = 0; for (int driverid : driverIds) { sumShell = 0; sumDea = 0; for (int car : carIds) { // shell sumShell += this->getMinimum(driverid, SHELL, rennid, car, minTimeRace); // dea sumDea += this->getMinimum(driverid, DEA, rennid, car, minTimeRace); } tempTimes.shell = sumShell / static_cast(carIds.size()); tempTimes.dea = sumDea / static_cast(carIds.size()); times.push_back(tempTimes); } this->plotDrivers(drivers, times); // clean up times.clear(); // calc cars for (int carId : carIds) { sumShell = 0; sumDea = 0; for (int driverId : driverIds) { // shell sumShell += this->getMinimum(driverId, SHELL, rennid, carId, minTimeRace); // dea sumDea += this->getMinimum(driverId, DEA, rennid, carId, minTimeRace); } tempTimes.shell = sumShell / static_cast(driverIds.size()); tempTimes.dea = sumDea / static_cast(driverIds.size()); times.push_back(tempTimes); } // calc car names vector carNames; for_each(carIds.begin(), carIds.end(), [&carNames, this](int id) { carNames.push_back(this->getAutoName(id)); }); plotCars(carNames, times); } Result::~Result() { cout << "result closed" << endl; } template T Result::myMin(vector vec) { T min; if (vec.size() > 0) { min = vec.at(0); } else { return 9999; } for (T minItr : vec) { if (min > minItr) { min = minItr; } } return min; } template double Result::meanVal(vector vec) { T sum = std::accumulate(vec.begin(), vec.end(), static_cast(0.0)); double mean = static_cast(sum) / vec.size(); return mean; } string Result::myRound(double x, int d = 0) { std::stringstream stream; stream << std::fixed << std::setprecision(d) << x; return stream.str(); } void Result::closeWindow() { this->close(); } vector Result::getFahrerIds(int rennid) { std::stringstream statement; statement << "select id_fahrer from zeiten where id_rennen like " << boost::lexical_cast(rennid) << " group by id_fahrer"; vector vecToRet; try { vector> ret = this->db->getData2(statement.str(), 1); for (size_t i = 0; i < ret.size(); i++) { string strValue = ret.at(i).at(0).toStdString(); vecToRet.push_back(boost::lexical_cast(strValue)); } return vecToRet; } catch (std::exception & e) { Q_UNUSED(e); cout << "FahrerIds konnten nicht aus Datenbank gelesen " "werden." << endl; } return vecToRet; } vector Result::getAutoIds(int rennid) { std::stringstream statement; statement << "select id_auto from zeiten where id_rennen like " << boost::lexical_cast(rennid) << " group by id_auto"; vector> ret = this->db->getData2(statement.str(), 1); vector vecToRet; try { vector> ret = this->db->getData2(statement.str(), 1); for (size_t i = 0; i < ret.size(); i++) { string strValue = ret.at(i).at(0).toStdString(); vecToRet.push_back(boost::lexical_cast(strValue)); } return vecToRet; } catch (std::exception & e) { Q_UNUSED(e); cout << "AutoIds konnten nicht aus Datenbank gelesen werden." << endl; } return vecToRet; } // returns valid minimal time in milliseconds int Result::getMinimum(int fahrerId, int bahnId, int rennId, int autoid, int minTime) { std::stringstream statement; statement << "select zeit from Zeiten where id_rennen like " << boost::lexical_cast(rennId) << " and id_fahrer like " << boost::lexical_cast(fahrerId) << " and id_auto like " << boost::lexical_cast(autoid) << " and id_bahn like " << boost::lexical_cast(bahnId); try { vector> res = this->db->getData2(statement.str(), 1); // filter impossible values vector validTimes; for (size_t i = 0; i < res.size(); i++) { int timeToCompare = res.at(i).at(0).toInt(); if (timeToCompare >= minTime) { validTimes.push_back(timeToCompare); } } if (validTimes.size() > 0) { std::vector::iterator result = std::min_element(validTimes.begin(), validTimes.end()); return *result; } else { cout << "no valid time found" << endl; return 9999; } } catch (std::exception & e) { Q_UNUSED(e); cout << "Minimalzeit konnte aus Datenbank nicht gelesen " "werden." << endl; } return 9999; } float Result::getMean(int fahrerid, int bahnid, int rennid) { vector autoids = this->getAutoIds(rennid); vector avg; for (int car : autoids) { avg.push_back( this->getMinimum(fahrerid, bahnid, rennid, car, this->minimumTime)); } int sum = std::accumulate(avg.begin(), avg.end(), 0); float floatAvg = 9999; if (avg.size() > 0) { floatAvg = static_cast(sum) / static_cast(avg.size()); cout << "avg:" << floatAvg << endl; return floatAvg; } return 9999; } // returns name of driver with id string Result::getFahrerName(int id) { std::stringstream statement; statement << "select name from fahrer where id like " << boost::lexical_cast(id); vector> result = this->db->getData2(statement.str(), 1); if (result.size() > 0) { try { return result.at(0).at(0).toStdString(); } catch (std::exception & e) { Q_UNUSED(e); cout << "Fehler beim Lesen vom Fahrernamen." << endl; return "Leer"; } } return "Leer"; } string Result::getAutoName(int id) { std::stringstream statement; statement << "select date from Rennen where id like " << boost::lexical_cast(this->rennid); string renndatum; try { QString qstrRenndatum = this->db->getData2(statement.str(), 1).at(0).at(0); renndatum = qstrRenndatum.toStdString(); } catch (std::exception & e) { Q_UNUSED(e); cout << "Renndatum konnte nicht gelesen werden." << endl; return "nix"; } try { // clear stringstream statement.str(std::string()); statement << "select name from Autokonfiguration where " "id_auto like " << boost::lexical_cast(id) << " and seit < '" << renndatum << "' order by seit DESC limit 1"; QString name = this->db->getData2(statement.str(), 1).at(0).at(0); return name.toStdString(); } catch (std::exception & e) { Q_UNUSED(e); } return "name"; } double Result::getMinRangeTime(vector times) { double min = 9999; for (struct Times time : times) { if (time.shell < min) { min = time.shell; } if (time.dea < min) { min = time.dea; } } min -= 100; cout << min << endl; return min / 1000; } double Result::getMaxRangeTime(vector times) { double max = 0; for (struct Times time : times) { if (time.shell > max) { max = time.shell; } if (time.dea > max) { max = time.dea; } } max += 200; return max / 1000; } void Result::plotCars(vector carNames, vector times) { // structure of times: Gnuplot gp; std::stringstream xlabels; xlabels << "set xtics("; for (size_t i = 0; i < carNames.size(); i++) { xlabels << "'" << carNames[i] << "' " << boost::lexical_cast(i + 0.15); if (i + 1 != carNames.size()) { xlabels << ", "; } else { xlabels << ")\n"; } } cout << xlabels.str(); gp << xlabels.str(); std::vector> xy_pts; for (size_t i = 0; i < carNames.size(); i++) { xy_pts.push_back(std::make_pair(i, (times.at(i).shell) / 1000.0)); // xy_pts.push_back(std::make_pair(i + 0.3, times.at(i).dea)); } double minRange = getMinRangeTime(times); double maxRange = getMaxRangeTime(times); string strMinRange = boost::str(boost::format("%.2f") % minRange); string strMaxRange = boost::str(boost::format("%.2f") % maxRange); double distance = (maxRange - minRange) / 35; cout << "renndatum: " << this->renndatum.toStdString() << endl; gp << "set yrange [" << strMinRange << ":" << strMaxRange << "]\n"; gp << "set term wxt title '" << this->renndatum.toStdString() << "'\n"; gp << "set boxwidth 0.3\nset style fill solid\n"; gp << "set title 'Vergleich der Autos'\n"; gp << "set ylabel 'Zeit in Sekunden'\n"; gp << "set xlabel 'Autos'\n"; gp << "show grid\nset grid ytics lc rgb '#bbbbbb' lw 1 lt 0\n"; gp << "plot" << gp.file1d(xy_pts) << "with boxes title 'Shell' lt rgb '#FF0000', '' u 1:($2 + " << distance << "):($2) with labels notitle" << std::endl; xy_pts.clear(); for (size_t i = 0; i < carNames.size(); i++) { // xy_pts.push_back(std::make_pair(i, times.at(i).shell)); xy_pts.push_back(std::make_pair(i + 0.3, (times.at(i).dea) / 1000.0)); } gp << "replot" << gp.file1d(xy_pts) << "with boxes title 'Dea' lt rgb '#00FF00', ''u 1:($2 + " << distance << "):($2) " "with labels notitle" << std::endl; } void Result::plotDrivers(vector driverNames, vector times) { // structure of times: Gnuplot gp; std::stringstream xlabels; xlabels << "set xtics("; for (size_t i = 0; i < driverNames.size(); i++) { xlabels << "'" << driverNames[i] << "' " << boost::lexical_cast(i + 0.15); if (i + 1 != driverNames.size()) { xlabels << ", "; } else { xlabels << ")\n"; } } gp << xlabels.str(); std::vector> xy_pts; for (size_t i = 0; i < driverNames.size(); i++) { xy_pts.push_back(std::make_pair(i, (times.at(i).shell) / 1000.0)); // xy_pts.push_back(std::make_pair(i + 0.3, times.at(i).dea)); } double minRange = getMinRangeTime(times); double maxRange = getMaxRangeTime(times); string strMinRange = boost::str(boost::format("%.2f") % minRange); string strMaxRange = boost::str(boost::format("%.2f") % maxRange); double distance = (maxRange - minRange) / 35; gp << "set yrange [" << strMinRange << ":" << strMaxRange << "]\n"; gp << "set term wxt title '" << this->renndatum.toStdString() << "'\n"; gp << "set boxwidth 0.3\nset style fill solid\n"; gp << "set title 'Vergleich der Fahrer'\n"; gp << "set ylabel 'Zeit in Sekunden'\n"; gp << "set xlabel 'Fahrer'\n"; gp << "show grid\nset grid ytics lc rgb '#bbbbbb' lw 1 lt 0\n"; gp << "plot" << gp.file1d(xy_pts) << "with boxes title 'Shell' lt rgb '#FF0000', '' u 1:($2 + " << distance << "):($2) with labels notitle" << std::endl; xy_pts.clear(); for (size_t i = 0; i < driverNames.size(); i++) { // xy_pts.push_back(std::make_pair(i, times.at(i).shell)); xy_pts.push_back(std::make_pair(i + 0.3, (times.at(i).dea) / 1000.0)); } gp << "replot" << gp.file1d(xy_pts) << "with boxes title 'Dea' lt rgb '#00FF00', ''u 1:($2 +" << distance << "):($2) " "with labels notitle" << std::endl; }