MeOS version 3.6.1109
This commit is contained in:
parent
06a6c4ff67
commit
7a99f0a4cd
@ -900,6 +900,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
|||||||
wstring firstStart = gdi.getText("FirstStart");
|
wstring firstStart = gdi.getText("FirstStart");
|
||||||
wstring minInterval = gdi.getText("MinInterval");
|
wstring minInterval = gdi.getText("MinInterval");
|
||||||
wstring vacances = gdi.getText("Vacances");
|
wstring vacances = gdi.getText("Vacances");
|
||||||
|
setDefaultVacant(vacances);
|
||||||
|
|
||||||
clearPage(gdi, false);
|
clearPage(gdi, false);
|
||||||
gdi.addString("", boldLarge, "Lotta flera klasser");
|
gdi.addString("", boldLarge, "Lotta flera klasser");
|
||||||
@ -1044,13 +1045,14 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
|||||||
gdi.addInput("FirstStart", oe->getAbsTime(3600), 10, 0, L"Första (ordinarie) start:");
|
gdi.addInput("FirstStart", oe->getAbsTime(3600), 10, 0, L"Första (ordinarie) start:");
|
||||||
gdi.addInput("MinInterval", L"2:00", 10, 0, L"Minsta startintervall:");
|
gdi.addInput("MinInterval", L"2:00", 10, 0, L"Minsta startintervall:");
|
||||||
gdi.fillDown();
|
gdi.fillDown();
|
||||||
gdi.addInput("Vacances", L"5%", 10, 0, L"Andel vakanser:");
|
gdi.addInput("Vacances", getDefaultVacant(), 10, 0, L"Andel vakanser:");
|
||||||
gdi.popX();
|
gdi.popX();
|
||||||
|
|
||||||
createDrawMethod(gdi);
|
createDrawMethod(gdi);
|
||||||
|
|
||||||
gdi.fillDown();
|
gdi.fillDown();
|
||||||
gdi.addCheckbox("LateBefore", "Efteranmälda före ordinarie");
|
gdi.addCheckbox("LateBefore", "Efteranmälda före ordinarie");
|
||||||
|
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, oe->getPropertyInt("DrawInterlace", 1) != 0);
|
||||||
gdi.dropLine();
|
gdi.dropLine();
|
||||||
|
|
||||||
gdi.popX();
|
gdi.popX();
|
||||||
@ -1180,8 +1182,11 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
wstring minInterval = gdi.getText("MinInterval");
|
wstring minInterval = gdi.getText("MinInterval");
|
||||||
wstring vacances = gdi.getText("Vacances");
|
wstring vacances = gdi.getText("Vacances");
|
||||||
bool lateBefore = false;
|
setDefaultVacant(vacances);
|
||||||
//bool pairwise = gdi.isChecked("Pairwise");
|
bool lateBefore = gdi.isChecked("LateBefore");
|
||||||
|
bool allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours");
|
||||||
|
oe->setProperty("DrawInterlace", allowNeighbourSameCourse ? 1 : 0);
|
||||||
|
|
||||||
int pairSize = 1;
|
int pairSize = 1;
|
||||||
if (gdi.hasField("PairSize")) {
|
if (gdi.hasField("PairSize")) {
|
||||||
pairSize = gdi.getSelectedItem("PairSize").first;
|
pairSize = gdi.getSelectedItem("PairSize").first;
|
||||||
@ -1201,7 +1206,7 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
|||||||
|
|
||||||
clearPage(gdi, true);
|
clearPage(gdi, true);
|
||||||
oe->automaticDrawAll(gdi, firstStart, minInterval, vacances,
|
oe->automaticDrawAll(gdi, firstStart, minInterval, vacances,
|
||||||
lateBefore, method, pairSize);
|
lateBefore, allowNeighbourSameCourse, method, pairSize);
|
||||||
oe->addAutoBib();
|
oe->addAutoBib();
|
||||||
gdi.scrollToBottom();
|
gdi.scrollToBottom();
|
||||||
gdi.addButton("Cancel", "Återgå", ClassesCB);
|
gdi.addButton("Cancel", "Återgå", ClassesCB);
|
||||||
@ -1263,10 +1268,19 @@ int TabClass::classCB(gdioutput &gdi, int type, void *data)
|
|||||||
int origin = bi.getExtraInt();
|
int origin = bi.getExtraInt();
|
||||||
wstring firstStart = oe->getAbsTime(3600);
|
wstring firstStart = oe->getAbsTime(3600);
|
||||||
wstring minInterval = L"2:00";
|
wstring minInterval = L"2:00";
|
||||||
wstring vacances = L"5%";
|
wstring vacances = getDefaultVacant();
|
||||||
|
if (gdi.hasField("Vacances")) {
|
||||||
|
vacances = gdi.getText("Vacances");
|
||||||
|
setDefaultVacant(vacances);
|
||||||
|
}
|
||||||
|
|
||||||
int maxNumControl = 1;
|
int maxNumControl = 1;
|
||||||
int pairSize = 1;
|
int pairSize = 1;
|
||||||
|
|
||||||
|
if (gdi.hasField("AllowNeighbours")) {
|
||||||
|
bool allowNeighbourSameCourse = gdi.isChecked("AllowNeighbours");
|
||||||
|
oe->setProperty("DrawInterlace", allowNeighbourSameCourse ? 1 : 0);
|
||||||
|
}
|
||||||
//bool pairwise = false;
|
//bool pairwise = false;
|
||||||
int by = 0;
|
int by = 0;
|
||||||
int bx = gdi.getCX();
|
int bx = gdi.getCX();
|
||||||
@ -4387,6 +4401,7 @@ void TabClass::readDrawInfo(gdioutput &gdi, DrawInfo &drawInfoOut) {
|
|||||||
|
|
||||||
int maxVacancy = gdi.getTextNo("VacancesMax");
|
int maxVacancy = gdi.getTextNo("VacancesMax");
|
||||||
int minVacancy = gdi.getTextNo("VacancesMin");
|
int minVacancy = gdi.getTextNo("VacancesMin");
|
||||||
|
setDefaultVacant(gdi.getText("Vacances"));
|
||||||
double vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
|
double vacancyFactor = 0.01*_wtof(gdi.getText("Vacances").c_str());
|
||||||
double extraFactor = 0.01*_wtof(gdi.getText("Extra").c_str());
|
double extraFactor = 0.01*_wtof(gdi.getText("Extra").c_str());
|
||||||
|
|
||||||
@ -4661,7 +4676,7 @@ void TabClass::loadBasicDrawSetup(gdioutput &gdi, int &bx, int &by, const wstrin
|
|||||||
gdi.popX();
|
gdi.popX();
|
||||||
gdi.dropLine(4);
|
gdi.dropLine(4);
|
||||||
gdi.fillDown();
|
gdi.fillDown();
|
||||||
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, oe->getPropertyInt("DrawInterlace", 1) == 0);
|
gdi.addCheckbox("AllowNeighbours", "Tillåt samma bana inom basintervall", 0, oe->getPropertyInt("DrawInterlace", 1) != 0);
|
||||||
gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false);
|
gdi.addCheckbox("CoursesTogether", "Lotta klasser med samma bana gemensamt", 0, false);
|
||||||
|
|
||||||
gdi.dropLine(0.5);
|
gdi.dropLine(0.5);
|
||||||
@ -4680,8 +4695,10 @@ void TabClass::loadBasicDrawSetup(gdioutput &gdi, int &bx, int &by, const wstrin
|
|||||||
gdi.fillRight();
|
gdi.fillRight();
|
||||||
gdi.popX();
|
gdi.popX();
|
||||||
gdi.addInput("Vacances", vacances, 6, 0, L"Andel vakanser:");
|
gdi.addInput("Vacances", vacances, 6, 0, L"Andel vakanser:");
|
||||||
gdi.addInput("VacancesMin", L"1", 6, 0, L"Min. vakanser (per klass):");
|
bool zeroVac = _wtoi(vacances.c_str()) == 0;
|
||||||
gdi.addInput("VacancesMax", L"10", 6, 0, L"Max. vakanser (per klass):");
|
|
||||||
|
gdi.addInput("VacancesMin", zeroVac ? L"0" : L"1", 6, 0, L"Min. vakanser (per klass):");
|
||||||
|
gdi.addInput("VacancesMax", zeroVac ? L"0" : L"10", 6, 0, L"Max. vakanser (per klass):");
|
||||||
gdi.addInput("Extra", L"0%", 6, 0, L"Förväntad andel efteranmälda:");
|
gdi.addInput("Extra", L"0%", 6, 0, L"Förväntad andel efteranmälda:");
|
||||||
|
|
||||||
gdi.dropLine(4);
|
gdi.dropLine(4);
|
||||||
@ -4749,3 +4766,17 @@ void TabClass::loadReadyToDistribute(gdioutput &gdi, int &bx, int &by) {
|
|||||||
|
|
||||||
gdi.refresh();
|
gdi.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wstring TabClass::getDefaultVacant() {
|
||||||
|
int dvac = oe->getPropertyInt("VacantPercent", -1);
|
||||||
|
if (dvac >= 0 && dvac <= 100)
|
||||||
|
return itow(dvac) + L" %";
|
||||||
|
else
|
||||||
|
return L"5 %";
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabClass::setDefaultVacant(const wstring &v) {
|
||||||
|
int val = _wtoi(v.c_str());
|
||||||
|
if (val >= 0 && val <= 100)
|
||||||
|
oe->setProperty("VacantPercent", val);
|
||||||
|
}
|
||||||
|
|||||||
@ -156,6 +156,9 @@ class TabClass :
|
|||||||
int maxNumControl, const wstring& minInterval, const wstring& vacances, const set<int> &clsId);
|
int maxNumControl, const wstring& minInterval, const wstring& vacances, const set<int> &clsId);
|
||||||
|
|
||||||
void loadReadyToDistribute(gdioutput &gdi, int &bx, int &by);
|
void loadReadyToDistribute(gdioutput &gdi, int &bx, int &by);
|
||||||
|
|
||||||
|
wstring getDefaultVacant();
|
||||||
|
void setDefaultVacant(const wstring &val);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void clearCompetitionData();
|
void clearCompetitionData();
|
||||||
|
|||||||
@ -1545,7 +1545,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
|||||||
|
|
||||||
switch (startType) {
|
switch (startType) {
|
||||||
case SMCommon:
|
case SMCommon:
|
||||||
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0", L"0", false, oEvent::DrawMethod::Random, 1);
|
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"0", L"0", false, false, oEvent::DrawMethod::Random, 1);
|
||||||
drawn = true;
|
drawn = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1570,7 +1570,7 @@ int TabCompetition::competitionCB(gdioutput &gdi, int type, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!skip)
|
if (!skip)
|
||||||
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00", L"2", true, oEvent::DrawMethod::MeOS, 1);
|
oe->automaticDrawAll(gdi, formatTimeHMS(firstStart), L"2:00", L"2", true, false, oEvent::DrawMethod::MeOS, 1);
|
||||||
drawn = true;
|
drawn = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1686,7 +1686,7 @@ bool Table::inputChange(gdioutput &gdi, HWND hdt)
|
|||||||
|
|
||||||
int Table::getColumn(int x, bool limit) const
|
int Table::getColumn(int x, bool limit) const
|
||||||
{
|
{
|
||||||
if (columns.empty())
|
if (columns.empty() || xpos.empty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (x<xpos[0]) {
|
if (x<xpos[0]) {
|
||||||
|
|||||||
@ -840,7 +840,7 @@ SI X är redan inläst. Ska den läsas in igen? = SI X is already read out. Read
|
|||||||
SI på = SI on
|
SI på = SI on
|
||||||
SI-dubbletter: %d = SI duplicates: %d
|
SI-dubbletter: %d = SI duplicates: %d
|
||||||
SOFT-avgift = SOFT fee
|
SOFT-avgift = SOFT fee
|
||||||
SOFT-lottning = Swedish draw method
|
SOFT-lottning = Swedish legacy draw method
|
||||||
Saknad starttid = Missing Start Time
|
Saknad starttid = Missing Start Time
|
||||||
Sammanställning = Summary
|
Sammanställning = Summary
|
||||||
Sammanställning, ekonomi = Summary, economy
|
Sammanställning, ekonomi = Summary, economy
|
||||||
|
|||||||
@ -179,8 +179,7 @@ void gdioutput::constructor(double _scale)
|
|||||||
|
|
||||||
void gdioutput::setFont(int size, const wstring &font)
|
void gdioutput::setFont(int size, const wstring &font)
|
||||||
{
|
{
|
||||||
//setEncoding(enc);
|
double s = 1 + double(size)*0.25;
|
||||||
double s = 1 + double(size)*0.25;// 1 + size * sqrt(double(size))*0.2;
|
|
||||||
initCommon(s, font);
|
initCommon(s, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
//V35: abcdef
|
//V35: abcdef
|
||||||
//V36: abcdef
|
//V36: abcdef
|
||||||
int getMeosBuild() {
|
int getMeosBuild() {
|
||||||
string revision("$Rev: 915 $");
|
string revision("$Rev: 935 $");
|
||||||
return 174 + atoi(revision.substr(5, string::npos).c_str());
|
return 174 + atoi(revision.substr(5, string::npos).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,12 +42,12 @@ int getMeosBuild() {
|
|||||||
//V33: abcdefghij
|
//V33: abcdefghij
|
||||||
//V34: abcdfge
|
//V34: abcdfge
|
||||||
wstring getMeosDate() {
|
wstring getMeosDate() {
|
||||||
wstring date(L"$Date: 2019-07-30 07:05:51 +0200 (ti, 30 jul 2019) $");
|
wstring date(L"$Date: 2019-10-05 21:53:12 +0200 (lö, 05 okt 2019) $");
|
||||||
return date.substr(7,10);
|
return date.substr(7,10);
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring getBuildType() {
|
wstring getBuildType() {
|
||||||
return L"Update 2"; // No parantheses (...)
|
return L"Update 3"; // No parantheses (...)
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring getMajorVersion() {
|
wstring getMajorVersion() {
|
||||||
@ -135,6 +135,13 @@ void getSupporters(vector<wstring> &supp, vector<wstring> &developSupp)
|
|||||||
supp.emplace_back(L"JWOC 2019");
|
supp.emplace_back(L"JWOC 2019");
|
||||||
developSupp.emplace_back(L"OK Nackhe");
|
developSupp.emplace_back(L"OK Nackhe");
|
||||||
supp.emplace_back(L"OK Rodhen");
|
supp.emplace_back(L"OK Rodhen");
|
||||||
|
supp.emplace_back(L"HEYRIES");
|
||||||
|
developSupp.emplace_back(L"SongTao Wang / Henan Zhixing Exploration Sports Culture Co., Ltd.");
|
||||||
|
developSupp.emplace_back(L"Australian and Oceania Orienteering Championships 2019");
|
||||||
|
supp.emplace_back(L"Järfälla OK");
|
||||||
|
supp.emplace_back(L"TJ Slávia Farmaceut Bratislava");
|
||||||
|
supp.emplace_back(L"OK Tyr, Karlstad");
|
||||||
|
supp.emplace_back(L"Magnus Thornell, Surahammars SOK");
|
||||||
|
|
||||||
reverse(supp.begin(), supp.end());
|
reverse(supp.begin(), supp.end());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,9 +71,7 @@ protected:
|
|||||||
mutable int tMapsUsed = -1;
|
mutable int tMapsUsed = -1;
|
||||||
mutable int tMapsUsedNoVacant = -1;
|
mutable int tMapsUsedNoVacant = -1;
|
||||||
|
|
||||||
// Get an identity sum based on controls
|
|
||||||
int getIdSum(int nControls);
|
|
||||||
|
|
||||||
/// Add an control without update
|
/// Add an control without update
|
||||||
pControl doAddControl(int Id);
|
pControl doAddControl(int Id);
|
||||||
|
|
||||||
@ -95,6 +93,9 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Get an identity sum based on controls
|
||||||
|
int getIdSum(int nControls);
|
||||||
|
|
||||||
void getClasses(vector<pClass> &usageClass) const;
|
void getClasses(vector<pClass> &usageClass) const;
|
||||||
|
|
||||||
void remove();
|
void remove();
|
||||||
|
|||||||
@ -799,10 +799,12 @@ bool oDataContainer::isModified(const oDataInfo &di,
|
|||||||
return memcmp(vd, vdOld, 8) != 0;
|
return memcmp(vd, vdOld, 8) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (di.Type == oDTString){
|
else if (di.Type == oDTString) {
|
||||||
char * vd=(char *)(data)+di.Index;
|
LPBYTE vdB = LPBYTE(data) + di.Index;
|
||||||
char * vdOld=(char *)(oldData)+di.Index;
|
LPBYTE vdOldB = LPBYTE(oldData) + di.Index;
|
||||||
return strcmp(vd, vdOld) != 0;
|
wchar_t * vd=(wchar_t *)vdB;
|
||||||
|
wchar_t * vdOld=(wchar_t *)vdOldB;
|
||||||
|
return wcscmp(vd, vdOld) != 0;
|
||||||
}
|
}
|
||||||
else if (di.Type == oDTStringDynamic){
|
else if (di.Type == oDTStringDynamic){
|
||||||
const wstring &newS = (*strptr)[0][di.Index];
|
const wstring &newS = (*strptr)[0][di.Index];
|
||||||
|
|||||||
@ -2604,7 +2604,6 @@ int oEvent::getRelativeTime(const string &date, const string &absoluteTime, cons
|
|||||||
else return -1;
|
else return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int oEvent::getRelativeTime(const wstring &m) const {
|
int oEvent::getRelativeTime(const wstring &m) const {
|
||||||
int dayIndex = 0;
|
int dayIndex = 0;
|
||||||
for (size_t k = 0; k + 1 < m.length(); k++) {
|
for (size_t k = 0; k + 1 < m.length(); k++) {
|
||||||
@ -2947,12 +2946,13 @@ void oEvent::generateVacancyList(gdioutput &gdi, GUICALLBACK cb)
|
|||||||
oRunnerList::iterator it;
|
oRunnerList::iterator it;
|
||||||
|
|
||||||
// BIB, START, NAME, CLUB, SI
|
// BIB, START, NAME, CLUB, SI
|
||||||
int dx[5]={0, 0, 70, 150};
|
int dx[5]={0, 0, gdi.scaleLength(70), gdi.scaleLength(150)};
|
||||||
|
|
||||||
bool withbib=hasBib(true, false);
|
bool withbib=hasBib(true, false);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (withbib) for (i=1;i<4;i++) dx[i]+=40;
|
const int bibLen = gdi.scaleLength(40);
|
||||||
|
if (withbib) for (i = 1; i < 4; i++) dx[i] += bibLen;
|
||||||
|
|
||||||
int y=gdi.getCY();
|
int y=gdi.getCY();
|
||||||
int x=gdi.getCX();
|
int x=gdi.getCX();
|
||||||
@ -2984,7 +2984,7 @@ void oEvent::generateVacancyList(gdioutput &gdi, GUICALLBACK cb)
|
|||||||
|
|
||||||
if (nRunner>=RunnersPerCol) {
|
if (nRunner>=RunnersPerCol) {
|
||||||
y = yStart;
|
y = yStart;
|
||||||
x += dx[3]+5;
|
x += dx[3]+gdi.scaleLength(5);
|
||||||
nRunner = 0;
|
nRunner = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -588,7 +588,7 @@ public:
|
|||||||
// Automatic draw of all classes
|
// Automatic draw of all classes
|
||||||
void automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
|
void automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
|
||||||
const wstring &minIntervall, const wstring &vacances,
|
const wstring &minIntervall, const wstring &vacances,
|
||||||
bool lateBefore, DrawMethod method, int pairSize);
|
bool lateBefore, bool allowNeighbourSameCourse, DrawMethod method, int pairSize);
|
||||||
|
|
||||||
// Restore a backup by renamning the file to .meos
|
// Restore a backup by renamning the file to .meos
|
||||||
void restoreBackup();
|
void restoreBackup();
|
||||||
@ -773,10 +773,6 @@ public:
|
|||||||
/** Use the current computer time to convert the specified time to a long time, if long times are used. */
|
/** Use the current computer time to convert the specified time to a long time, if long times are used. */
|
||||||
int convertToFullTime(int inTime);
|
int convertToFullTime(int inTime);
|
||||||
|
|
||||||
/** Internal version of start order optimizer */
|
|
||||||
void optimizeStartOrder(vector< vector<pair<int, int> > > &StartField, DrawInfo &drawInfo,
|
|
||||||
vector<ClassInfo> &cInfo, int useNControls, int alteration);
|
|
||||||
|
|
||||||
struct ResultEvent {
|
struct ResultEvent {
|
||||||
ResultEvent() {}
|
ResultEvent() {}
|
||||||
ResultEvent(pRunner r, int time, int control, RunnerStatus status):
|
ResultEvent(pRunner r, int time, int control, RunnerStatus status):
|
||||||
|
|||||||
@ -421,6 +421,328 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DrawOptimAlgo {
|
||||||
|
private:
|
||||||
|
oEvent * oe;
|
||||||
|
vector<pClass> Classes;
|
||||||
|
vector<pRunner> Runners;
|
||||||
|
|
||||||
|
int maxNRunner = 0;
|
||||||
|
int maxGroup = 0;
|
||||||
|
int maxCourse = 0;
|
||||||
|
int bestEndPos = 0;
|
||||||
|
|
||||||
|
map<int, ClassInfo> otherClasses;
|
||||||
|
|
||||||
|
int bestEndPosGlobal = 0;
|
||||||
|
|
||||||
|
static int optimalLayout(int interval, vector< pair<int, int> > &classes) {
|
||||||
|
sort(classes.begin(), classes.end());
|
||||||
|
|
||||||
|
vector<int> chaining(interval, 0);
|
||||||
|
|
||||||
|
for (int k = int(classes.size()) - 1; k >= 0; k--) {
|
||||||
|
int ix = 0;
|
||||||
|
// Find free position
|
||||||
|
for (int i = 1; i<interval; i++) {
|
||||||
|
if (chaining[i] < chaining[ix])
|
||||||
|
ix = i;
|
||||||
|
}
|
||||||
|
int nr = classes[k].first;
|
||||||
|
if (chaining[ix] > 0)
|
||||||
|
nr += classes[k].second;
|
||||||
|
|
||||||
|
chaining[ix] += 1 + interval * (nr - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int last = chaining[0];
|
||||||
|
for (int i = 1; i<interval; i++) {
|
||||||
|
last = max(chaining[i], last);
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void computeBestStartDepth(DrawInfo &di, vector<ClassInfo> &cInfo, int useNControls, int alteration) {
|
||||||
|
//OutputDebugString((L"Use NC:" + itow(useNControls)).c_str());
|
||||||
|
if (di.firstStart <= 0)
|
||||||
|
di.firstStart = 0;
|
||||||
|
|
||||||
|
otherClasses.clear();
|
||||||
|
cInfo.clear();
|
||||||
|
map<int, int> runnerPerGroup;
|
||||||
|
map<int, int> runnerPerCourse;
|
||||||
|
int nRunnersTot = 0;
|
||||||
|
for (auto c_it : Classes) {
|
||||||
|
bool drawClass = di.classes.count(c_it->getId()) > 0;
|
||||||
|
ClassInfo *cPtr = 0;
|
||||||
|
|
||||||
|
if (!drawClass) {
|
||||||
|
otherClasses[c_it->getId()] = ClassInfo(&*c_it);
|
||||||
|
cPtr = &otherClasses[c_it->getId()];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cPtr = &di.classes[c_it->getId()];
|
||||||
|
|
||||||
|
ClassInfo &ci = *cPtr;
|
||||||
|
pCourse pc = c_it->getCourse();
|
||||||
|
|
||||||
|
if (pc && useNControls < 1000) {
|
||||||
|
if (useNControls > 0 && pc->getNumControls() > 0)
|
||||||
|
ci.unique = 1000000 + pc->getIdSum(useNControls);
|
||||||
|
else
|
||||||
|
ci.unique = 10000 + pc->getId();
|
||||||
|
|
||||||
|
ci.courseId = pc->getId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ci.unique = ci.classId;
|
||||||
|
|
||||||
|
if (!drawClass)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int nr = c_it->getNumRunners(true, true, true);
|
||||||
|
if (ci.nVacant == -1 || !ci.nVacantSpecified || di.changedVacancyInfo) {
|
||||||
|
// Auto initialize
|
||||||
|
int nVacancies = int(nr * di.vacancyFactor + 0.5);
|
||||||
|
nVacancies = max(nVacancies, di.minVacancy);
|
||||||
|
nVacancies = min(nVacancies, di.maxVacancy);
|
||||||
|
nVacancies = max(nVacancies, 0);
|
||||||
|
|
||||||
|
if (di.vacancyFactor == 0)
|
||||||
|
nVacancies = 0;
|
||||||
|
|
||||||
|
ci.nVacant = nVacancies;
|
||||||
|
ci.nVacantSpecified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ci.nExtraSpecified || di.changedExtraInfo) {
|
||||||
|
// Auto initialize
|
||||||
|
ci.nExtra = max(int(nr * di.extraFactor + 0.5), 1);
|
||||||
|
|
||||||
|
if (di.extraFactor == 0)
|
||||||
|
ci.nExtra = 0;
|
||||||
|
ci.nExtraSpecified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ci.nRunners = nr + ci.nVacant;
|
||||||
|
|
||||||
|
if (ci.nRunners > 0) {
|
||||||
|
nRunnersTot += ci.nRunners + ci.nExtra;
|
||||||
|
cInfo.push_back(ci);
|
||||||
|
runnerPerGroup[ci.unique] += ci.nRunners + ci.nExtra;
|
||||||
|
runnerPerCourse[ci.courseId] += ci.nRunners + ci.nExtra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
maxGroup = 0;
|
||||||
|
maxCourse = 0;
|
||||||
|
maxNRunner = 0;
|
||||||
|
int a = 1 + (alteration % 7);
|
||||||
|
int b = (alteration % 3);
|
||||||
|
int c = alteration % 5;
|
||||||
|
|
||||||
|
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
maxNRunner = max(maxNRunner, cInfo[k].nRunners);
|
||||||
|
cInfo[k].nRunnersGroup = runnerPerGroup[cInfo[k].unique];
|
||||||
|
cInfo[k].nRunnersCourse = runnerPerCourse[cInfo[k].courseId];
|
||||||
|
maxGroup = max(maxGroup, cInfo[k].nRunnersGroup);
|
||||||
|
maxCourse = max(maxCourse, cInfo[k].nRunnersCourse);
|
||||||
|
cInfo[k].sortFactor = cInfo[k].nRunners * a + cInfo[k].nRunnersGroup * b + cInfo[k].nRunnersCourse * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
auto pc = oe->getClass(cInfo[k].classId);
|
||||||
|
auto c = pc->getCourse();
|
||||||
|
wstring cc;
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
cc += itow(c->getControl(i)->getId()) + L",";
|
||||||
|
wstring w = pc->getName() + L"; " + cc + L"; " + itow(cInfo[k].unique) + L"; " + itow(cInfo[k].nRunners) + L"\n";
|
||||||
|
OutputDebugString(w.c_str());
|
||||||
|
}*/
|
||||||
|
|
||||||
|
di.numDistinctInit = runnerPerGroup.size();
|
||||||
|
di.numRunnerSameInitMax = maxGroup;
|
||||||
|
di.numRunnerSameCourseMax = maxCourse;
|
||||||
|
// Calculate the theoretical best end position to use.
|
||||||
|
bestEndPos = 0;
|
||||||
|
|
||||||
|
for (map<int, int>::iterator it = runnerPerGroup.begin(); it != runnerPerGroup.end(); ++it) {
|
||||||
|
vector< pair<int, int> > classes;
|
||||||
|
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
if (cInfo[k].unique == it->first)
|
||||||
|
classes.push_back(make_pair(cInfo[k].nRunners, cInfo[k].nExtra));
|
||||||
|
}
|
||||||
|
int optTime = optimalLayout(di.minClassInterval / di.baseInterval, classes);
|
||||||
|
bestEndPos = max(optTime, bestEndPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nRunnersTot > 0)
|
||||||
|
bestEndPos = max(bestEndPos, nRunnersTot / di.nFields);
|
||||||
|
|
||||||
|
if (!di.allowNeighbourSameCourse)
|
||||||
|
bestEndPos = max(bestEndPos, maxCourse * 2 - 1);
|
||||||
|
else
|
||||||
|
bestEndPos = max(bestEndPos, maxCourse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DrawOptimAlgo(oEvent *oe) : oe(oe) {
|
||||||
|
oe->getClasses(Classes, false);
|
||||||
|
oe->getRunners(-1, -1, Runners);
|
||||||
|
}
|
||||||
|
|
||||||
|
void optimizeStartOrder(vector< vector<pair<int, int> > > &StartField, DrawInfo &di,
|
||||||
|
vector<ClassInfo> &cInfo, int useNControls, int alteration) {
|
||||||
|
|
||||||
|
if (bestEndPosGlobal == 0) {
|
||||||
|
bestEndPosGlobal = 100000;
|
||||||
|
for (int i = 1; i <= di.maxCommonControl && i<=10; i++) {
|
||||||
|
int ncc = i;
|
||||||
|
if (i >= 10)
|
||||||
|
ncc = 0;
|
||||||
|
computeBestStartDepth(di, cInfo, ncc, 0);
|
||||||
|
bestEndPosGlobal = min(bestEndPos, bestEndPosGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
|
di.minimalStartDepth = bestEndPosGlobal * di.baseInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
computeBestStartDepth(di, cInfo, useNControls, alteration);
|
||||||
|
|
||||||
|
ClassInfo::sSortOrder = 0;
|
||||||
|
sort(cInfo.begin(), cInfo.end());
|
||||||
|
|
||||||
|
int maxSize = di.minClassInterval * maxNRunner;
|
||||||
|
|
||||||
|
// Special case for constant time start
|
||||||
|
if (di.baseInterval == 0) {
|
||||||
|
di.baseInterval = 1;
|
||||||
|
di.minClassInterval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate an estimated maximal class intervall
|
||||||
|
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
int quotient = maxSize / (cInfo[k].nRunners*di.baseInterval);
|
||||||
|
|
||||||
|
if (quotient*di.baseInterval > di.maxClassInterval)
|
||||||
|
quotient = di.maxClassInterval / di.baseInterval;
|
||||||
|
|
||||||
|
if (cInfo[k].nRunnersGroup >= maxGroup)
|
||||||
|
quotient = di.minClassInterval / di.baseInterval;
|
||||||
|
|
||||||
|
if (!cInfo[k].hasFixedTime)
|
||||||
|
cInfo[k].interval = quotient;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int m = 0; m < di.nFields; m++)
|
||||||
|
StartField[m].resize(3000);
|
||||||
|
|
||||||
|
int alternator = 0;
|
||||||
|
|
||||||
|
// Fill up with non-drawn classes
|
||||||
|
for (auto &it : Runners) {
|
||||||
|
int st = it->getStartTime();
|
||||||
|
int relSt = st - di.firstStart;
|
||||||
|
int relPos = relSt / di.baseInterval;
|
||||||
|
|
||||||
|
if (st > 0 && relSt >= 0 && relPos < 3000 && (relSt%di.baseInterval) == 0) {
|
||||||
|
if (otherClasses.count(it->getClassId(false)) == 0)
|
||||||
|
continue;
|
||||||
|
pClass cls = it->getClassRef(true);
|
||||||
|
if (cls) {
|
||||||
|
if (!di.startName.empty() && cls->getStart() != di.startName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cls->hasFreeStart())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassInfo &ci = otherClasses[it->getClassId(false)];
|
||||||
|
int k = 0;
|
||||||
|
while (true) {
|
||||||
|
if (k == StartField.size()) {
|
||||||
|
StartField.push_back(vector< pair<int, int> >());
|
||||||
|
StartField.back().resize(3000);
|
||||||
|
}
|
||||||
|
if (StartField[k][relPos].first == 0) {
|
||||||
|
StartField[k][relPos].first = ci.unique;
|
||||||
|
StartField[k][relPos].second = ci.courseId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill up classes with fixed starttime
|
||||||
|
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
if (cInfo[k].hasFixedTime) {
|
||||||
|
insertStart(StartField, di.nFields, cInfo[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (di.minClassInterval == 0) {
|
||||||
|
// Set fixed start time
|
||||||
|
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
if (cInfo[k].hasFixedTime)
|
||||||
|
continue;
|
||||||
|
cInfo[k].firstStart = di.firstStart;
|
||||||
|
cInfo[k].interval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Do the distribution
|
||||||
|
for (size_t k = 0; k < cInfo.size(); k++) {
|
||||||
|
if (cInfo[k].hasFixedTime)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int minPos = 1000000;
|
||||||
|
int minEndPos = 1000000;
|
||||||
|
int minInterval = cInfo[k].interval;
|
||||||
|
|
||||||
|
for (int i = di.minClassInterval / di.baseInterval; i <= cInfo[k].interval; i++) {
|
||||||
|
|
||||||
|
int startpos = alternator % max(1, (bestEndPos - cInfo[k].nRunners * i) / 3);
|
||||||
|
startpos = 0;
|
||||||
|
int ipos = startpos;
|
||||||
|
int t = 0;
|
||||||
|
|
||||||
|
while (!isFree(di, StartField, di.nFields, ipos, i, cInfo[k])) {
|
||||||
|
t++;
|
||||||
|
|
||||||
|
// Algorithm to randomize start position
|
||||||
|
// First startpos -> bestEndTime, then 0 -> startpos, then remaining
|
||||||
|
if (t < (bestEndPos - startpos))
|
||||||
|
ipos = startpos + t;
|
||||||
|
else {
|
||||||
|
ipos = t - (bestEndPos - startpos);
|
||||||
|
if (ipos >= startpos)
|
||||||
|
ipos = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int endPos = ipos + i * cInfo[k].nRunners;
|
||||||
|
if (endPos < minEndPos || endPos < bestEndPos) {
|
||||||
|
minEndPos = endPos;
|
||||||
|
minPos = ipos;
|
||||||
|
minInterval = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cInfo[k].firstStart = minPos;
|
||||||
|
cInfo[k].interval = minInterval;
|
||||||
|
cInfo[k].overShoot = max(minEndPos - bestEndPosGlobal, 0);
|
||||||
|
insertStart(StartField, di.nFields, cInfo[k]);
|
||||||
|
|
||||||
|
alternator += alteration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void oEvent::optimizeStartOrder(gdioutput &gdi, DrawInfo &di, vector<ClassInfo> &cInfo)
|
void oEvent::optimizeStartOrder(gdioutput &gdi, DrawInfo &di, vector<ClassInfo> &cInfo)
|
||||||
{
|
{
|
||||||
if (Classes.size()==0)
|
if (Classes.size()==0)
|
||||||
@ -439,12 +761,15 @@ void oEvent::optimizeStartOrder(gdioutput &gdi, DrawInfo &di, vector<ClassInfo>
|
|||||||
int nCtrl = 1;//max(1, di.maxCommonControl-2);
|
int nCtrl = 1;//max(1, di.maxCommonControl-2);
|
||||||
const int maxControlDiff = di.maxCommonControl < 1000 ? di.maxCommonControl : 10;
|
const int maxControlDiff = di.maxCommonControl < 1000 ? di.maxCommonControl : 10;
|
||||||
bool checkOnlyClass = di.maxCommonControl == 1000;
|
bool checkOnlyClass = di.maxCommonControl == 1000;
|
||||||
|
|
||||||
|
DrawOptimAlgo drawOptim(this);
|
||||||
|
|
||||||
while (!found) {
|
while (!found) {
|
||||||
|
|
||||||
StartParam optInner;
|
StartParam optInner;
|
||||||
for (int alt = 0; alt <= 20 && !found; alt++) {
|
for (int alt = 0; alt <= 20 && !found; alt++) {
|
||||||
vector< vector<pair<int, int> > > startField(di.nFields);
|
vector< vector<pair<int, int> > > startField(di.nFields);
|
||||||
optimizeStartOrder(startField, di, cInfo, nCtrl, alt);
|
drawOptim.optimizeStartOrder(startField, di, cInfo, nCtrl, alt);
|
||||||
|
|
||||||
int overShoot = 0;
|
int overShoot = 0;
|
||||||
int overSum = 0;
|
int overSum = 0;
|
||||||
@ -495,7 +820,7 @@ void oEvent::optimizeStartOrder(gdioutput &gdi, DrawInfo &di, vector<ClassInfo>
|
|||||||
}
|
}
|
||||||
|
|
||||||
vector< vector<pair<int, int> > > startField(di.nFields);
|
vector< vector<pair<int, int> > > startField(di.nFields);
|
||||||
optimizeStartOrder(startField, di, cInfo, opt.nControls, opt.alternator);
|
drawOptim.optimizeStartOrder(startField, di, cInfo, opt.nControls, opt.alternator);
|
||||||
|
|
||||||
gdi.addString("", 0, "Identifierar X unika inledningar på banorna.#" + itos(di.numDistinctInit));
|
gdi.addString("", 0, "Identifierar X unika inledningar på banorna.#" + itos(di.numDistinctInit));
|
||||||
gdi.addString("", 0, "Största gruppen med samma inledning har X platser.#" + itos(di.numRunnerSameInitMax));
|
gdi.addString("", 0, "Största gruppen med samma inledning har X platser.#" + itos(di.numRunnerSameInitMax));
|
||||||
@ -545,33 +870,6 @@ void oEvent::optimizeStartOrder(gdioutput &gdi, DrawInfo &di, vector<ClassInfo>
|
|||||||
gdi.dropLine();
|
gdi.dropLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
int optimalLayout(int interval, vector< pair<int, int> > &classes) {
|
|
||||||
sort(classes.begin(), classes.end());
|
|
||||||
|
|
||||||
vector<int> chaining(interval, 0);
|
|
||||||
|
|
||||||
for (int k = int(classes.size())-1 ; k >= 0; k--) {
|
|
||||||
int ix = 0;
|
|
||||||
// Find free position
|
|
||||||
for (int i = 1; i<interval; i++) {
|
|
||||||
if (chaining[i] < chaining[ix])
|
|
||||||
ix = i;
|
|
||||||
}
|
|
||||||
int nr = classes[k].first;
|
|
||||||
if (chaining[ix] > 0)
|
|
||||||
nr += classes[k].second;
|
|
||||||
|
|
||||||
chaining[ix] += 1 + interval*(nr-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int last = chaining[0];
|
|
||||||
for (int i = 1; i<interval; i++) {
|
|
||||||
last = max(chaining[i], last);
|
|
||||||
}
|
|
||||||
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
void oEvent::loadDrawSettings(const set<int> &classes, DrawInfo &drawInfo, vector<ClassInfo> &cInfo) const {
|
void oEvent::loadDrawSettings(const set<int> &classes, DrawInfo &drawInfo, vector<ClassInfo> &cInfo) const {
|
||||||
drawInfo.firstStart = 3600 * 22;
|
drawInfo.firstStart = 3600 * 22;
|
||||||
drawInfo.minClassInterval = 3600;
|
drawInfo.minClassInterval = 3600;
|
||||||
@ -656,250 +954,6 @@ void oEvent::loadDrawSettings(const set<int> &classes, DrawInfo &drawInfo, vecto
|
|||||||
cInfo[k].nRunnersCourse = runnerPerCourse[cInfo[k].courseId];
|
cInfo[k].nRunnersCourse = runnerPerCourse[cInfo[k].courseId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void oEvent::optimizeStartOrder(vector< vector<pair<int, int> > > &StartField, DrawInfo &di,
|
|
||||||
vector<ClassInfo> &cInfo, int useNControls, int alteration)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (di.firstStart<=0)
|
|
||||||
di.firstStart = 0;
|
|
||||||
|
|
||||||
if (di.minClassInterval < di.baseInterval) {
|
|
||||||
throw meosException("Startintervallet får inte vara kortare än basintervallet.");
|
|
||||||
}
|
|
||||||
|
|
||||||
map<int, ClassInfo> otherClasses;
|
|
||||||
cInfo.clear();
|
|
||||||
oClassList::iterator c_it;
|
|
||||||
map<int, int> runnerPerGroup;
|
|
||||||
map<int, int> runnerPerCourse;
|
|
||||||
int nRunnersTot = 0;
|
|
||||||
for (c_it=Classes.begin(); c_it != Classes.end(); ++c_it) {
|
|
||||||
bool drawClass = di.classes.count(c_it->getId())>0;
|
|
||||||
ClassInfo *cPtr = 0;
|
|
||||||
|
|
||||||
if (!drawClass) {
|
|
||||||
otherClasses[c_it->getId()] = ClassInfo(&*c_it);
|
|
||||||
cPtr = &otherClasses[c_it->getId()];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cPtr = &di.classes[c_it->getId()];
|
|
||||||
|
|
||||||
ClassInfo &ci = *cPtr;
|
|
||||||
pCourse pc = c_it->getCourse();
|
|
||||||
|
|
||||||
if (pc && useNControls < 1000) {
|
|
||||||
if (useNControls>0 && pc->nControls>0)
|
|
||||||
ci.unique = 1000000 + pc->getIdSum(useNControls);
|
|
||||||
else
|
|
||||||
ci.unique = 10000 + pc->getId();
|
|
||||||
|
|
||||||
ci.courseId = pc->getId();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ci.unique = ci.classId;
|
|
||||||
|
|
||||||
if (!drawClass)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int nr = c_it->getNumRunners(true, true, true);
|
|
||||||
if (ci.nVacant == -1 || !ci.nVacantSpecified || di.changedVacancyInfo) {
|
|
||||||
// Auto initialize
|
|
||||||
int nVacancies = int(nr * di.vacancyFactor + 0.5);
|
|
||||||
nVacancies = max(nVacancies, di.minVacancy);
|
|
||||||
nVacancies = min(nVacancies, di.maxVacancy);
|
|
||||||
nVacancies = max(nVacancies, 0);
|
|
||||||
|
|
||||||
if (di.vacancyFactor == 0)
|
|
||||||
nVacancies = 0;
|
|
||||||
|
|
||||||
ci.nVacant = nVacancies;
|
|
||||||
ci.nVacantSpecified = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ci.nExtraSpecified || di.changedExtraInfo) {
|
|
||||||
// Auto initialize
|
|
||||||
ci.nExtra = max(int(nr * di.extraFactor + 0.5), 1);
|
|
||||||
|
|
||||||
if (di.extraFactor == 0)
|
|
||||||
ci.nExtra = 0;
|
|
||||||
ci.nExtraSpecified = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ci.nRunners = nr + ci.nVacant;
|
|
||||||
|
|
||||||
if (ci.nRunners>0) {
|
|
||||||
nRunnersTot += ci.nRunners + ci.nExtra;
|
|
||||||
cInfo.push_back(ci);
|
|
||||||
runnerPerGroup[ci.unique] += ci.nRunners + ci.nExtra;
|
|
||||||
runnerPerCourse[ci.courseId] += ci.nRunners + ci.nExtra;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int maxGroup = 0;
|
|
||||||
int maxCourse = 0;
|
|
||||||
int maxNRunner = 0;
|
|
||||||
int a = 1 + (alteration % 7);
|
|
||||||
int b = (alteration % 3);
|
|
||||||
int c = alteration % 5;
|
|
||||||
|
|
||||||
for (size_t k = 0; k<cInfo.size(); k++) {
|
|
||||||
maxNRunner = max(maxNRunner, cInfo[k].nRunners);
|
|
||||||
cInfo[k].nRunnersGroup = runnerPerGroup[cInfo[k].unique];
|
|
||||||
cInfo[k].nRunnersCourse = runnerPerCourse[cInfo[k].courseId];
|
|
||||||
maxGroup = max(maxGroup, cInfo[k].nRunnersGroup);
|
|
||||||
maxCourse = max(maxCourse, cInfo[k].nRunnersCourse);
|
|
||||||
cInfo[k].sortFactor = cInfo[k].nRunners * a + cInfo[k].nRunnersGroup * b + cInfo[k].nRunnersCourse * c;
|
|
||||||
}
|
|
||||||
|
|
||||||
di.numDistinctInit = runnerPerGroup.size();
|
|
||||||
di.numRunnerSameInitMax = maxGroup;
|
|
||||||
di.numRunnerSameCourseMax = maxCourse;
|
|
||||||
// Calculate the theoretical best end position to use.
|
|
||||||
int bestEndPos = 0;
|
|
||||||
|
|
||||||
for (map<int, int>::iterator it = runnerPerGroup.begin(); it != runnerPerGroup.end(); ++it) {
|
|
||||||
vector< pair<int, int> > classes;
|
|
||||||
for (size_t k = 0; k<cInfo.size(); k++) {
|
|
||||||
if (cInfo[k].unique == it->first)
|
|
||||||
classes.push_back(make_pair(cInfo[k].nRunners, cInfo[k].nExtra));
|
|
||||||
}
|
|
||||||
int optTime = optimalLayout(di.minClassInterval/di.baseInterval, classes);
|
|
||||||
bestEndPos = max(optTime, bestEndPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nRunnersTot > 0)
|
|
||||||
bestEndPos = max(bestEndPos, nRunnersTot / di.nFields);
|
|
||||||
|
|
||||||
bestEndPos = max(bestEndPos, maxCourse * 2);
|
|
||||||
|
|
||||||
di.minimalStartDepth = bestEndPos * di.baseInterval;
|
|
||||||
|
|
||||||
ClassInfo::sSortOrder = 0;
|
|
||||||
sort(cInfo.begin(), cInfo.end());
|
|
||||||
|
|
||||||
int maxSize = di.minClassInterval * maxNRunner;
|
|
||||||
|
|
||||||
// Special case for constant time start
|
|
||||||
if (di.baseInterval==0) {
|
|
||||||
di.baseInterval = 1;
|
|
||||||
di.minClassInterval = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate an estimated maximal class intervall
|
|
||||||
for (size_t k = 0; k < cInfo.size(); k++) {
|
|
||||||
int quotient = maxSize/(cInfo[k].nRunners*di.baseInterval);
|
|
||||||
|
|
||||||
if (quotient*di.baseInterval > di.maxClassInterval)
|
|
||||||
quotient=di.maxClassInterval/di.baseInterval;
|
|
||||||
|
|
||||||
if (cInfo[k].nRunnersGroup >= maxGroup)
|
|
||||||
quotient = di.minClassInterval / di.baseInterval;
|
|
||||||
|
|
||||||
if (!cInfo[k].hasFixedTime)
|
|
||||||
cInfo[k].interval = quotient;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int m=0;m < di.nFields;m++)
|
|
||||||
StartField[m].resize(3000);
|
|
||||||
|
|
||||||
int alternator = 0;
|
|
||||||
|
|
||||||
// Fill up with non-drawn classes
|
|
||||||
for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) {
|
|
||||||
int st = it->getStartTime();
|
|
||||||
int relSt = st-di.firstStart;
|
|
||||||
int relPos = relSt / di.baseInterval;
|
|
||||||
|
|
||||||
if (st>0 && relSt>=0 && relPos<3000 && (relSt%di.baseInterval) == 0) {
|
|
||||||
if (otherClasses.count(it->getClassId(false))==0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!di.startName.empty() && it->Class && it->Class->getStart()!=di.startName)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ClassInfo &ci = otherClasses[it->getClassId(false)];
|
|
||||||
int k = 0;
|
|
||||||
while(true) {
|
|
||||||
if (k==StartField.size()) {
|
|
||||||
StartField.push_back(vector< pair<int, int> >());
|
|
||||||
StartField.back().resize(3000);
|
|
||||||
}
|
|
||||||
if (StartField[k][relPos].first==0) {
|
|
||||||
StartField[k][relPos].first = ci.unique;
|
|
||||||
StartField[k][relPos].second = ci.courseId;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill up classes with fixed starttime
|
|
||||||
for (size_t k = 0; k < cInfo.size(); k++) {
|
|
||||||
if (cInfo[k].hasFixedTime) {
|
|
||||||
insertStart(StartField, di.nFields, cInfo[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (di.minClassInterval == 0) {
|
|
||||||
// Set fixed start time
|
|
||||||
for (size_t k = 0; k < cInfo.size(); k++) {
|
|
||||||
if (cInfo[k].hasFixedTime)
|
|
||||||
continue;
|
|
||||||
cInfo[k].firstStart = di.firstStart;
|
|
||||||
cInfo[k].interval = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Do the distribution
|
|
||||||
for (size_t k = 0; k < cInfo.size(); k++) {
|
|
||||||
if (cInfo[k].hasFixedTime)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int minPos = 1000000;
|
|
||||||
int minEndPos = 1000000;
|
|
||||||
int minInterval=cInfo[k].interval;
|
|
||||||
|
|
||||||
for (int i = di.minClassInterval/di.baseInterval; i<=cInfo[k].interval; i++) {
|
|
||||||
|
|
||||||
int startpos = alternator % max(1, (bestEndPos - cInfo[k].nRunners * i)/3);
|
|
||||||
startpos = 0;
|
|
||||||
int ipos = startpos;
|
|
||||||
int t = 0;
|
|
||||||
|
|
||||||
while( !isFree(di, StartField, di.nFields, ipos, i, cInfo[k]) ) {
|
|
||||||
t++;
|
|
||||||
|
|
||||||
// Algorithm to randomize start position
|
|
||||||
// First startpos -> bestEndTime, then 0 -> startpos, then remaining
|
|
||||||
if (t<(bestEndPos-startpos))
|
|
||||||
ipos = startpos + t;
|
|
||||||
else {
|
|
||||||
ipos = t - (bestEndPos-startpos);
|
|
||||||
if (ipos>=startpos)
|
|
||||||
ipos = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int endPos = ipos + i*cInfo[k].nRunners;
|
|
||||||
if (endPos < minEndPos || endPos < bestEndPos) {
|
|
||||||
minEndPos = endPos;
|
|
||||||
minPos = ipos;
|
|
||||||
minInterval = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cInfo[k].firstStart = minPos;
|
|
||||||
cInfo[k].interval = minInterval;
|
|
||||||
cInfo[k].overShoot = max(minEndPos - bestEndPos, 0);
|
|
||||||
insertStart(StartField, di.nFields, cInfo[k]);
|
|
||||||
|
|
||||||
alternator += alteration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void oEvent::drawRemaining(DrawMethod method, bool placeAfter)
|
void oEvent::drawRemaining(DrawMethod method, bool placeAfter)
|
||||||
{
|
{
|
||||||
DrawType drawType = placeAfter ? DrawType::RemainingAfter : DrawType::RemainingBefore;
|
DrawType drawType = placeAfter ? DrawType::RemainingAfter : DrawType::RemainingBefore;
|
||||||
@ -1271,7 +1325,7 @@ void oEvent::drawListClumped(int ClassID, int FirstStart, int Interval, int Vaca
|
|||||||
|
|
||||||
void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
|
void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
|
||||||
const wstring &minIntervall, const wstring &vacances,
|
const wstring &minIntervall, const wstring &vacances,
|
||||||
bool lateBefore, DrawMethod method, int pairSize)
|
bool lateBefore, bool allowNeighbourSameCourse, DrawMethod method, int pairSize)
|
||||||
{
|
{
|
||||||
gdi.refresh();
|
gdi.refresh();
|
||||||
const int leg = 0;
|
const int leg = 0;
|
||||||
@ -1403,6 +1457,7 @@ void oEvent::automaticDrawAll(gdioutput &gdi, const wstring &firstStart,
|
|||||||
di.minVacancy = 1;
|
di.minVacancy = 1;
|
||||||
di.maxVacancy = 100;
|
di.maxVacancy = 100;
|
||||||
di.vacancyFactor = vacancy;
|
di.vacancyFactor = vacancy;
|
||||||
|
di.allowNeighbourSameCourse = allowNeighbourSameCourse;
|
||||||
|
|
||||||
di.startName = start;
|
di.startName = start;
|
||||||
|
|
||||||
|
|||||||
@ -3136,8 +3136,13 @@ bool oRunner::apply(bool sync, pRunner src, bool setTmpOnly) {
|
|||||||
tLeg = -1;
|
tLeg = -1;
|
||||||
tLegEquClass = 0;
|
tLegEquClass = 0;
|
||||||
tUseStartPunch=true;
|
tUseStartPunch=true;
|
||||||
if (tInTeam)
|
if (tInTeam) {
|
||||||
tInTeam->apply(sync, this, setTmpOnly);
|
tInTeam->apply(sync, this, setTmpOnly);
|
||||||
|
if (Class && Class->isQualificationFinalBaseClass()) {
|
||||||
|
if (tLeg > 0 && Class == getClassRef(true))
|
||||||
|
tNeedNoCard = true; // Not qualified
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (Class && Class->hasMultiCourse()) {
|
if (Class && Class->hasMultiCourse()) {
|
||||||
pClass pc=Class;
|
pClass pc=Class;
|
||||||
|
|||||||
@ -142,6 +142,12 @@ void pdfwriter::selectFont(HPDF_Page page, const PDFFontSet &fs, int format, flo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float fontFromGdiScale(double gdiScale) {
|
||||||
|
double f = max(1.0, min(gdiScale, 3.0))-1.0;
|
||||||
|
double s = 1.05 + 0.75*f;
|
||||||
|
return float(s);
|
||||||
|
}
|
||||||
|
|
||||||
void pdfwriter::generatePDF(const gdioutput &gdi,
|
void pdfwriter::generatePDF(const gdioutput &gdi,
|
||||||
const wstring &file,
|
const wstring &file,
|
||||||
const wstring &pageTitleW,
|
const wstring &pageTitleW,
|
||||||
@ -206,7 +212,9 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
|
|||||||
float w = HPDF_Page_GetWidth(page);
|
float w = HPDF_Page_GetWidth(page);
|
||||||
float h = HPDF_Page_GetHeight(page);
|
float h = HPDF_Page_GetHeight(page);
|
||||||
float scale = (w / maxX) * 0.95f;
|
float scale = (w / maxX) * 0.95f;
|
||||||
float fontScale = 1.5f;
|
|
||||||
|
double gdiScale = gdi.getScale();
|
||||||
|
const float fontScale = fontFromGdiScale(gdiScale);
|
||||||
|
|
||||||
vector<RenderedPage> pages;
|
vector<RenderedPage> pages;
|
||||||
PageInfo pageInfo;
|
PageInfo pageInfo;
|
||||||
@ -243,33 +251,33 @@ void pdfwriter::generatePDF(const gdioutput &gdi,
|
|||||||
if (fonts.count(info[k].ti.font) == 0) {
|
if (fonts.count(info[k].ti.font) == 0) {
|
||||||
FontInfo fi;
|
FontInfo fi;
|
||||||
gdi.getFontInfo(info[k].ti, fi);
|
gdi.getFontInfo(info[k].ti, fi);
|
||||||
float fontScale;
|
float fontScaleLoc;
|
||||||
wstring tmpFile;
|
wstring tmpFile;
|
||||||
fonts[info[k].ti.font] = fs; //Default fallback
|
fonts[info[k].ti.font] = fs; //Default fallback
|
||||||
PDFFontSet &f = fonts[info[k].ti.font];
|
PDFFontSet &f = fonts[info[k].ti.font];
|
||||||
|
|
||||||
HPDF_Font font = getPDFFont(fi.normal, float(gdi.getScale()), tmpFile, fontScale);
|
HPDF_Font font = getPDFFont(fi.normal, float(gdi.getScale()), tmpFile, fontScaleLoc);
|
||||||
if (!tmpFile.empty())
|
if (!tmpFile.empty())
|
||||||
tmpFiles.push_back(tmpFile);
|
tmpFiles.push_back(tmpFile);
|
||||||
if (font) {
|
if (font) {
|
||||||
f.font = font;
|
f.font = font;
|
||||||
f.fontScale = fontScale;
|
f.fontScale = fontScaleLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
font = getPDFFont(fi.italic, float(gdi.getScale()), tmpFile, fontScale);
|
font = getPDFFont(fi.italic, float(gdi.getScale()), tmpFile, fontScaleLoc);
|
||||||
if (!tmpFile.empty())
|
if (!tmpFile.empty())
|
||||||
tmpFiles.push_back(tmpFile);
|
tmpFiles.push_back(tmpFile);
|
||||||
if (font) {
|
if (font) {
|
||||||
f.fontItalic = font;
|
f.fontItalic = font;
|
||||||
f.fontScaleItalic = fontScale;
|
f.fontScaleItalic = fontScaleLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
font = getPDFFont(fi.bold, (float)gdi.getScale(), tmpFile, fontScale);
|
font = getPDFFont(fi.bold, (float)gdi.getScale(), tmpFile, fontScaleLoc);
|
||||||
if (!tmpFile.empty())
|
if (!tmpFile.empty())
|
||||||
tmpFiles.push_back(tmpFile);
|
tmpFiles.push_back(tmpFile);
|
||||||
if (font) {
|
if (font) {
|
||||||
f.fontBold = font;
|
f.fontBold = font;
|
||||||
f.fontScaleBold = fontScale;
|
f.fontScaleBold = fontScaleLoc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -835,7 +835,7 @@ SI X är redan inläst. Ska den läsas in igen? = SI X är redan inläst. Ska de
|
|||||||
SI på = SI på
|
SI på = SI på
|
||||||
SI-dubbletter: %d = SI-dubbletter: %d
|
SI-dubbletter: %d = SI-dubbletter: %d
|
||||||
SOFT-avgift = SOFT-avgift
|
SOFT-avgift = SOFT-avgift
|
||||||
SOFT-lottning = SOFT-lottning
|
SOFT-lottning = Äldre SOFT-lottning
|
||||||
Saknad starttid = Saknad starttid
|
Saknad starttid = Saknad starttid
|
||||||
Sammanställning = Sammanställning
|
Sammanställning = Sammanställning
|
||||||
Sammanställning, ekonomi = Sammanställning, ekonomi
|
Sammanställning, ekonomi = Sammanställning, ekonomi
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user