2024-08-02 16:07:15 +02:00
|
|
|
#include "Sport.h"
|
2024-08-16 07:06:05 +02:00
|
|
|
#include "Competitor.h"
|
2024-08-05 14:47:45 +02:00
|
|
|
|
|
|
|
// categories
|
2024-08-15 21:24:28 +02:00
|
|
|
#include <QNetworkReply>
|
|
|
|
#include <qlogging.h>
|
|
|
|
#include <qobject.h>
|
2024-08-02 16:07:15 +02:00
|
|
|
#include <set>
|
2024-08-05 14:47:45 +02:00
|
|
|
|
|
|
|
// sorting and filtering
|
2024-08-04 22:56:15 +02:00
|
|
|
#include <map>
|
2024-08-03 20:19:05 +02:00
|
|
|
#include <algorithm>
|
2024-08-03 23:08:57 +02:00
|
|
|
#include <regex>
|
2024-08-02 16:07:15 +02:00
|
|
|
|
2024-08-05 14:47:45 +02:00
|
|
|
// float to string formatting
|
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
|
|
|
|
2024-08-02 16:07:15 +02:00
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonValueRef>
|
|
|
|
#include <QString>
|
2024-08-04 22:56:15 +02:00
|
|
|
|
2024-08-15 21:24:28 +02:00
|
|
|
namespace {
|
2024-08-16 15:40:37 +02:00
|
|
|
const QString &k_requestUrl = "https://sph-s-api.olympics.com/summer/schedules/api/ENG/schedule/discipline/";
|
2024-08-15 21:24:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SportModel::SportModel(QObject *parent) : QAbstractListModel(parent) {
|
|
|
|
}
|
|
|
|
|
|
|
|
int SportModel::rowCount(const QModelIndex &parent) const {
|
|
|
|
Q_UNUSED(parent);
|
|
|
|
return m_sportList.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant SportModel::data(const QModelIndex &index, int role) const {
|
|
|
|
if (index.isValid() && index.row() >= 0 && index.row() < m_sportList.size()) {
|
2024-08-16 07:06:05 +02:00
|
|
|
EventInfo *event = m_sportList[index.row()];
|
2024-08-15 21:24:28 +02:00
|
|
|
|
2024-08-16 07:06:05 +02:00
|
|
|
switch ((Role) role) {
|
|
|
|
case EventName:
|
|
|
|
return event->eventName();
|
|
|
|
|
|
|
|
case Competitors:
|
|
|
|
return event->competitors();
|
|
|
|
}
|
2024-08-15 21:24:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QHash<int, QByteArray> SportModel::roleNames() const {
|
|
|
|
QHash<int, QByteArray> names;
|
2024-08-16 07:06:05 +02:00
|
|
|
names[EventName] = "eventName";
|
|
|
|
names[Competitors] = "competitors";
|
2024-08-15 21:24:28 +02:00
|
|
|
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2024-08-16 15:40:37 +02:00
|
|
|
QString SportModel::discipline() const {
|
|
|
|
return m_discipline;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SportModel::setDiscipline(const QString &discipline) {
|
|
|
|
m_discipline = discipline;
|
2024-08-16 16:17:16 +02:00
|
|
|
disciplineChanged();
|
2024-08-16 15:40:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SportModel::request(QString discipline) {
|
2024-08-16 16:17:16 +02:00
|
|
|
setDiscipline(discipline);
|
2024-08-16 15:40:37 +02:00
|
|
|
m_reply = m_networkManager.get(QNetworkRequest( k_requestUrl + m_discipline));
|
2024-08-15 21:24:28 +02:00
|
|
|
qDebug() << m_reply;
|
|
|
|
connect(m_reply, &QNetworkReply::finished, this, &SportModel::parseData);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SportModel::parseData() {
|
|
|
|
|
|
|
|
if (m_reply->error() == QNetworkReply::NoError) {
|
|
|
|
beginResetModel();
|
2024-08-16 15:40:37 +02:00
|
|
|
qDeleteAll(m_sportList);
|
|
|
|
m_sportList.clear();
|
2024-08-15 21:24:28 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QByteArray strReply = m_reply->readAll();
|
|
|
|
|
|
|
|
//parse json
|
|
|
|
// qDebug() << "Response:" << strReply;
|
|
|
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(strReply);
|
|
|
|
|
|
|
|
QJsonArray sports = jsonDocument["units"].toArray();
|
|
|
|
for (const auto &sport : sports) {
|
|
|
|
QJsonObject entry = sport.toObject();
|
2024-08-16 07:06:05 +02:00
|
|
|
|
|
|
|
EventInfo *event = new EventInfo(this);
|
|
|
|
event->setEventName(entry["eventUnitName"].toString());
|
|
|
|
|
|
|
|
QList<QString> competitors;
|
|
|
|
for (const auto &competitor : entry["competitors"].toArray()) {
|
|
|
|
competitors << competitor.toObject()["name"].toString();
|
|
|
|
}
|
|
|
|
event->setCompetitors(competitors);
|
|
|
|
|
2024-08-15 21:24:28 +02:00
|
|
|
qDebug() << entry["eventUnitName"].toString();
|
2024-08-16 07:06:05 +02:00
|
|
|
m_sportList << event;
|
2024-08-15 21:24:28 +02:00
|
|
|
}
|
|
|
|
endResetModel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
// QJsonArray filter function, provide with input array and evaluation function
|
|
|
|
QJsonArray filter(QJsonArray input, function<bool (QJsonObject)> eval) {
|
|
|
|
QJsonArray output;
|
|
|
|
|
|
|
|
for (const QJsonValueRef &elemRef :input) {
|
|
|
|
QJsonObject elem = elemRef.toObject();
|
|
|
|
if(eval(elem)) {
|
|
|
|
output.append(elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
2024-08-02 16:07:15 +02:00
|
|
|
|
2024-08-03 23:08:57 +02:00
|
|
|
/**
|
|
|
|
* @brief Sport::lastName Reduce the full name to the part that is marked in capital letters (probably last name).
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::lastName(QList<Competitor> &competitors) {
|
2024-08-05 13:08:44 +02:00
|
|
|
// validate competitors
|
2024-08-15 20:41:08 +02:00
|
|
|
if (competitors.isEmpty()) return;
|
2024-08-05 13:08:44 +02:00
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
for (Competitor comp : competitors) {
|
|
|
|
string fullName = comp.getName().toUtf8().constData();
|
2024-08-03 23:08:57 +02:00
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
// regex to identify names, written in CAPS
|
2024-08-03 23:08:57 +02:00
|
|
|
regex r("[A-Z']{2,}");
|
|
|
|
smatch m;
|
|
|
|
|
|
|
|
regex_search(fullName, m, r);
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
// combine found names again
|
2024-08-03 23:08:57 +02:00
|
|
|
string lastName = "";
|
2024-08-05 13:08:44 +02:00
|
|
|
for (string s : m) lastName = lastName + s + " ";
|
|
|
|
|
|
|
|
// remove last space
|
2024-08-15 20:41:08 +02:00
|
|
|
QString name = QString(lastName.substr(0, lastName.size() - 1).c_str());
|
2024-08-03 23:08:57 +02:00
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
// replace competitor name in list
|
|
|
|
comp.setName(name);
|
2024-08-03 23:08:57 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-02 16:07:15 +02:00
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
/**
|
|
|
|
* @brief Sport::validateDiscipline Validates the discipline object. Checks for the units attribute.
|
|
|
|
* @return True, if discipline contains units.
|
|
|
|
*/
|
|
|
|
bool Sport::validateDiscipline() {
|
|
|
|
return this->discipline.contains("units");
|
|
|
|
}
|
|
|
|
|
2024-08-02 16:07:15 +02:00
|
|
|
/**
|
|
|
|
* @brief Sport::getCategories Reads all possible categories (also called units).
|
|
|
|
* @return A set of all category names.
|
|
|
|
*/
|
|
|
|
set<QString> Sport::getCategories() {
|
|
|
|
set<QString> categoryNames;
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
if (!validateDiscipline()) return categoryNames;
|
|
|
|
|
|
|
|
// search in each unit for the category (named "eventUnitName")
|
|
|
|
for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) {
|
|
|
|
QJsonObject unit = unitRef.toObject();
|
|
|
|
|
|
|
|
// validate unit
|
|
|
|
if (!unit.contains("eventUnitName")) continue;
|
|
|
|
|
|
|
|
categoryNames.insert(unit["eventUnitName"].toString());
|
2024-08-02 16:07:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return categoryNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::getCompetitorsByCategory Searches for all competitors, who took part in the given category.
|
|
|
|
* @param category The category to search in.
|
|
|
|
* @return An QJsonArray with all competitors as QJsonValueRef, which can be casted to QJsonObject.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
QList<CompetitorWithResults> Sport::getCompetitorsByCategory(QString category) {
|
|
|
|
QList<CompetitorWithResults> competitors;
|
2024-08-02 16:07:15 +02:00
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
if (!validateDiscipline()) return competitors;
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
for (const QJsonValueRef &unitRef : this->discipline["units"].toArray()) {
|
2024-08-02 16:07:15 +02:00
|
|
|
QJsonObject unit = unitRef.toObject();
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
// validate unit
|
|
|
|
if (!unit.contains("eventUnitName") || !unit.contains("competitors")) continue;
|
|
|
|
|
2024-08-02 16:07:15 +02:00
|
|
|
// search all units with the same category
|
2024-08-04 22:56:15 +02:00
|
|
|
if (unit["eventUnitName"].toString().compare(category, Qt::CaseSensitive) != 0) continue;
|
|
|
|
|
|
|
|
// add all competitors from one unit
|
2024-08-05 13:08:44 +02:00
|
|
|
for (const QJsonValueRef &compRef : unit["competitors"].toArray()) {
|
2024-08-15 20:41:08 +02:00
|
|
|
competitors.push_back(CompetitorWithResults(compRef.toObject()));
|
2024-08-04 22:56:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
return competitors;
|
2024-08-04 22:56:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::getCompetitorsWithMedal Filters all competitors, who have at least one medal. These objects are different from getCompetitorsByCategory !!!
|
|
|
|
* @return All competitors, who won at least one medal. Structure of one competitor: {code, name, noc, medals{ME_GOLD, ME_SILVER, ME_BRONZE}}
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
QList<MedalWinner> Sport::getCompetitorsWithMedal() {
|
2024-08-04 22:56:15 +02:00
|
|
|
map<QString, QJsonObject> competitors;
|
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
if (!validateDiscipline()) return QList<MedalWinner>();
|
2024-08-05 13:08:44 +02:00
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
// filter all units, which have medal events
|
|
|
|
QJsonArray units = filter(this->discipline["units"].toArray(), [](QJsonObject unit){
|
|
|
|
// search all units with Final, Gold or Bronze in their name, because these are the categories with the medal winners
|
|
|
|
QString unitName = unit["eventUnitName"].toString();
|
|
|
|
return unitName.contains("Bronze", Qt::CaseSensitive)
|
|
|
|
|| unitName.contains("Gold", Qt::CaseSensitive)
|
|
|
|
|| unitName.contains("Final", Qt::CaseSensitive);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (const QJsonValueRef &unitRef : units) {
|
|
|
|
QJsonObject unit = unitRef.toObject();
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
// validate unit
|
|
|
|
if (!unit.contains("competitors")) continue;
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
// filter all competitors, who won medals
|
|
|
|
QJsonArray medalComps = filter(unit["competitors"].toArray(), [](QJsonObject comp) {
|
|
|
|
if (!comp.contains("results")) return false;
|
2024-08-02 16:07:15 +02:00
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
QString medalType = comp["results"].toObject()["medalType"].toString();
|
|
|
|
return !medalType.isEmpty();
|
|
|
|
});
|
|
|
|
|
|
|
|
for (const QJsonValueRef &medalCompRef : medalComps) {
|
|
|
|
QJsonObject medalComp = medalCompRef.toObject();
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
// validate competitor (with medal)
|
|
|
|
if (!medalComp.contains("name")
|
|
|
|
|| !medalComp.contains("results")
|
|
|
|
|| !medalComp["results"].toObject().contains("medalType")) continue;
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
QString name = medalComp["name"].toString();
|
|
|
|
QString medalType = medalComp["results"].toObject()["medalType"].toString();
|
|
|
|
|
|
|
|
// check if competitor has other medal(s)
|
|
|
|
if (competitors.find(name) == competitors.end()) {
|
|
|
|
competitors.insert({name, createCompetitorWithMedals(medalComp)});
|
2024-08-02 16:07:15 +02:00
|
|
|
}
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
// update the medal count
|
|
|
|
QJsonObject updatedMedalCount = QJsonObject(competitors.find(name)->second["medals"].toObject());
|
|
|
|
|
|
|
|
int amount = updatedMedalCount[medalType].toInt() + 1;
|
|
|
|
updatedMedalCount.remove(medalType);
|
|
|
|
updatedMedalCount.insert(medalType, amount);
|
|
|
|
|
|
|
|
// create new medals QJsonObject and set it in the map
|
|
|
|
competitors.find(name)->second["medals"] = updatedMedalCount;
|
2024-08-02 16:07:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
// convert map to QJsonArray
|
2024-08-15 20:41:08 +02:00
|
|
|
QList<MedalWinner> output;
|
2024-08-04 22:56:15 +02:00
|
|
|
for (const pair<QString, QJsonObject> &competitor : competitors) {
|
2024-08-15 20:41:08 +02:00
|
|
|
output.append(MedalWinner(competitor.second));
|
2024-08-04 22:56:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
/**
|
|
|
|
* @brief Sport::createCompetitorWithMedals Creates a competitor QJsonObject with the following attributes: code, name, noc, medals{ME_GOLD, ME_SILVER, ME_BRONZE}
|
|
|
|
* @param comp The original competitor object.
|
|
|
|
* @return A competitor object with medal counts.
|
|
|
|
*/
|
2024-08-04 22:56:15 +02:00
|
|
|
QJsonObject Sport::createCompetitorWithMedals(QJsonObject comp) {
|
2024-08-05 13:08:44 +02:00
|
|
|
// repair competitor if something is missing
|
|
|
|
if (!comp.contains("code")) comp.insert("code", "0");
|
|
|
|
if (!comp.contains("name")) comp.insert("code", "");
|
|
|
|
if (!comp.contains("noc")) comp.insert("code", "");
|
|
|
|
|
2024-08-04 22:56:15 +02:00
|
|
|
// create new competitor QJsonObject and add it to the competitor map
|
|
|
|
QJsonObject medals {
|
|
|
|
{"ME_GOLD", 0},
|
|
|
|
{"ME_SILVER", 0},
|
|
|
|
{"ME_BRONZE", 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
QJsonObject medalComp {
|
|
|
|
{"code", comp["code"].toString()},
|
|
|
|
{"name", comp["name"].toString()},
|
|
|
|
{"noc", comp["noc"].toString()},
|
|
|
|
{"medals", medals}
|
|
|
|
};
|
|
|
|
|
|
|
|
return medalComp;
|
2024-08-03 20:19:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::filterByName Filter the competitors by name (case insensitive).
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
* @param name The (part of the) name to search for.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::filterByName(QList<Competitor> &competitors, QString name) {
|
|
|
|
filterCompetitors(competitors, name);
|
2024-08-03 20:19:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::filterByCountry Filter the competitors by their national olympics comittee (case insensitive, short form).
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
* @param nocShort The (part of the) national olympics comittee short name to search for.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::filterByCountry(QList<Competitor> &competitors, QString nocShort) {
|
|
|
|
filterCompetitors(competitors, nocShort);
|
2024-08-03 20:19:05 +02:00
|
|
|
}
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
/**
|
|
|
|
* @brief Sport::filterCompetitors Filters the given QJsonArray by comparing the value of a certain attribute with the given filter string.
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
* @param attribute The attribute to filter by.
|
|
|
|
* @param filter The string, which should be contained.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::filterCompetitors(QList<Competitor> &competitors, QString filter) {
|
|
|
|
for (qsizetype i = 0; i < competitors.size(); i++) {
|
|
|
|
if (competitors.value(i).getNOC().contains(filter)) {
|
|
|
|
competitors.remove(i);
|
2024-08-03 20:19:05 +02:00
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::sortByName Sort the competitors by their name (alphabetical, ascending).
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::sortByName(QList<Competitor> &competitors) {
|
|
|
|
if (competitors.isEmpty()) return;
|
|
|
|
sort(competitors.begin(), competitors.end(), Competitor::compareName);
|
2024-08-02 16:07:15 +02:00
|
|
|
}
|
2024-08-03 20:19:05 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::sortByCountry Sort the competitors by their national olympic comittee short name (alphabetical, ascending).
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::sortByCountry(QList<Competitor> &competitors) {
|
|
|
|
if (competitors.isEmpty()) return;
|
|
|
|
sort(competitors.begin(), competitors.end(), Competitor::compareNOC);
|
2024-08-03 20:19:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::sortByResult Sort the competitors by their results in one specific category (numerical, ascending).
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::sortByResult(QList<CompetitorWithResults> &competitors) {
|
2024-08-04 22:56:15 +02:00
|
|
|
if (competitors.isEmpty()) return;
|
2024-08-15 20:41:08 +02:00
|
|
|
sort(competitors.begin(), competitors.end(), CompetitorWithResults::compare);
|
2024-08-03 20:19:05 +02:00
|
|
|
}
|
|
|
|
|
2024-08-05 13:08:44 +02:00
|
|
|
/**
|
2024-08-15 20:41:08 +02:00
|
|
|
* @brief Sport::sortByMedals Sort the competitors by their medal amounts in one specific category (numerical, ascending).
|
2024-08-05 13:08:44 +02:00
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::sortByMedals(QList<MedalWinner> &competitors) {
|
|
|
|
if (competitors.isEmpty()) return;
|
|
|
|
sort(competitors.begin(), competitors.end(), MedalWinner::compare);
|
2024-08-03 20:19:05 +02:00
|
|
|
}
|
|
|
|
|
2024-08-05 14:47:45 +02:00
|
|
|
/**
|
|
|
|
* @brief Sport::reverseOrder Reverses the order of the competitors.
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::reverseOrder(QList<Competitor> &competitors) {
|
2024-08-05 14:47:45 +02:00
|
|
|
int iterations = competitors.size() / 2; // automatically rounds down
|
|
|
|
|
|
|
|
for (int i = 0; i < iterations; i++) {
|
2024-08-15 20:41:08 +02:00
|
|
|
Competitor temp = competitors.value(i);
|
|
|
|
competitors.replace(i, competitors.value(competitors.size() - 1 - i));
|
|
|
|
competitors.replace(competitors.size() - 1 - i, temp);
|
2024-08-05 14:47:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::addRelativeToFirst Adds a relative value to the result of all competitors. Relative to the first competitor in the QJsonArray.
|
|
|
|
* Stores the statistic in obj->results->stat for each competitor.
|
|
|
|
* @param competitors The competitors of one category.
|
|
|
|
*/
|
2024-08-15 20:41:08 +02:00
|
|
|
void Sport::addRelativeToFirst(QList<CompetitorWithResults> &competitors) {
|
2024-08-05 14:47:45 +02:00
|
|
|
if (competitors.isEmpty()) return;
|
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
QString reference = competitors.value(0).getMark();
|
2024-08-05 14:47:45 +02:00
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
for (CompetitorWithResults comp : competitors) {
|
|
|
|
QString results = comp.getMark();
|
2024-08-05 14:47:45 +02:00
|
|
|
|
|
|
|
// format relative float value to string with 2 digits after decimal point and sign
|
|
|
|
stringstream sstream;
|
2024-08-15 20:41:08 +02:00
|
|
|
sstream << fixed << setprecision(2) << calcRelativeStat(reference, results["mark"].toString());
|
2024-08-05 14:47:45 +02:00
|
|
|
QString stat(sstream.str().c_str());
|
|
|
|
stat.append("%");
|
|
|
|
if (stat.at(0).isNumber()) stat = QString("+").append(stat);
|
|
|
|
|
2024-08-15 20:41:08 +02:00
|
|
|
comp.setStatistic(stat);
|
2024-08-05 14:47:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sport::calcRelativeStat Calculates the relative deviation of val from ref in percent.
|
|
|
|
* @param ref The reference value.
|
|
|
|
* @param val The value to calculate the deviation from.
|
|
|
|
* @return The deviation from ref to val in percent.
|
|
|
|
*/
|
|
|
|
float Sport::calcRelativeStat(QString ref, QString val) {
|
|
|
|
// check if the value is not a time
|
|
|
|
if (!ref.contains(":") && !val.contains(":")) {
|
|
|
|
float fRef = ref.toFloat();
|
|
|
|
|
|
|
|
if (fRef == 0) return 0.0;
|
|
|
|
return ((val.toFloat() * 100)/ fRef) - 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
regex r("\\d+");
|
|
|
|
smatch mref, mval;
|
|
|
|
string sref = ref.toUtf8().constData();
|
|
|
|
string sval = val.toUtf8().constData();
|
|
|
|
|
|
|
|
regex_search(sref, mref, r);
|
|
|
|
regex_search(sval, mval, r);
|
|
|
|
|
|
|
|
float timeRef = stof(mref.str(1)) * 60 * 100 + stof(mref.str(2)) * 100 + stof(mref.str(3));
|
|
|
|
float timeVal = stof(mval.str(1)) * 60 * 100 + stof(mval.str(2)) * 100 + stof(mval.str(3));
|
|
|
|
|
|
|
|
return ((timeVal * 100) / timeRef) - 100;
|
|
|
|
}
|