-
Notifications
You must be signed in to change notification settings - Fork 0
/
linerunner.cpp
285 lines (265 loc) · 8.04 KB
/
linerunner.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#include <fstream>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <vector>
using namespace std;
struct Runner
{
string name;
string color;
};
struct Run
{
string name;
string color;
double days = 0;
double time = 0;
};
struct Category
{
string name;
vector<Run> runs;
};
struct GraphProperties
{
bool randomColors;
double circleRadius;
double lineWidth;
double xScale;
double yScale;
double width;
double height;
double lowestTime;
};
string RandomHex()
{
string hex = "0123456789abcdef";
string s(1, hex[rand() % 16]);
return s;
}
string RandomColor()
{
string start = "#";
return start.append(RandomHex()).append(RandomHex()).append(RandomHex()).append(RandomHex()).append(RandomHex()).append(RandomHex());
}
string GetRunnerColor(vector<Runner>& runners, string name)
{
for (Runner& runner : runners)
{
if (!strcmp(runner.name.c_str(), name.c_str()))
{
return runner.color;
}
}
return "";
}
void ParseFile(ifstream& ReadFile, vector<Runner>& runners, vector<Category>& categories, GraphProperties& props)
{
string textLine;
string category;
string name;
double days;
double time;
double biggestTime = 0;
double smallestTime = FLT_MAX;
bool useCategories = false;
while (getline(ReadFile, textLine))
{
//skip any blank lines
if (textLine.size() == 0)
continue;
//string 1: Category keyword, or runner name
size_t s1End = textLine.find(',');
string str1 = textLine.substr(0, s1End);
if (s1End == string::npos || str1.size() == 0)
{
cout << "Line '" << textLine << "' did not have 1st string. (Runner name)\n";
continue;
}
//string 2: Name of category, or days since beginning point that run happened on
size_t s2Start = s1End + 1;
size_t s2End = textLine.find(',', s2Start + 1);
string str2 = textLine.substr(s2Start, s2End - s2Start);
if (s2Start == string::npos || s2End == string::npos || str2.size() == 0)
{
cout << "Line '" << textLine << "' did not have 2nd string. (Days or category name) First string was '" << str1 << "'.\n";
continue;
}
//string 3: Run time. Should not exist if using category keyword.
size_t s3Start = s2End + 1;
string str3 = textLine.substr(s3Start, textLine.size() - s3Start);
bool no3rdCell = false;
if (s3Start == string::npos || str3.size() == 0)
no3rdCell = true;
if (str1 == "category" || str1 == "Category")
{
//no fear
//what if there was a runner named category?
//one fear
if (no3rdCell)
{
if (category.size() > 0)
{
cout << "End of category named '" << category << "'.\n";
}
cout << "Starting category named '" << str2 << "'.\n";
category = str2;
useCategories = true;
name.clear();
Category newCat;
newCat.name = category;
categories.push_back(newCat);
continue;
}
}
else if (no3rdCell)
{
cout << "Line '" << textLine << "' did not have 3rd string (Run time) and this line wasn't telling us about a new category. First string was '" << str1 << "'. Second string was '" << str2 << "'.\n";
continue;
}
name = str1;
days = atof(str2.c_str());
if (days > props.width)
props.width = days;
time = atof(str3.c_str());
if (time > biggestTime)
biggestTime = time;
if (time < smallestTime)
smallestTime = time;
//if this runner's name is new to us, add to the list
bool bNewRunner = true;
int k = -1;
for (Runner& runner : runners)
{
k++;
if (!strcmp(runner.name.c_str(), name.c_str()))
{
bNewRunner = false;
break;
}
}
if (bNewRunner)
{
Runner pNewRunner;
pNewRunner.name = name;
runners.push_back(pNewRunner);
k = (int)runners.size() - 1;
}
Run newRun;
newRun.name = runners[k].name;
newRun.color = runners[k].color;
newRun.days = days;
newRun.time = time;
//find category to add us to
for (Category& cat : categories)
{
if (cat.name == category)
{
cat.runs.push_back(newRun);
}
}
cout << "Runner '" << newRun.name << "' did a run " << newRun.days << " days after start, with a time of " << newRun.time << " seconds.\n";
}
props.height = biggestTime - smallestTime;
props.lowestTime = smallestTime;
}
int main(int argc, char* argv[])
{
vector<Runner> runners;
vector<Category> categories;
GraphProperties props;
bool debug = argc == 1;
props.randomColors = false;
string answer;
string clrAnswer;
string path = debug ? "data.csv" : argv[1];
ifstream ReadFile(path);
string base_filename = path.substr(path.find_last_of("/\\") + 1);
string::size_type const p(base_filename.find_last_of('.'));
string file_without_extension = base_filename.substr(0, p);
ofstream writingFile;
writingFile.open(file_without_extension + ".svg");
ParseFile(ReadFile, runners, categories, props);
cout << "\nGot file " << path << "\n";
cout << "Do you want individual colors for every runner?\nType 1 to use individual colors for every runner, then press ENTER.\n2 to use the same color for all runners.\n";
getline(cin, answer);
if (answer == "1")
{
for (Runner& runner : runners)
{
cout << "Please enter color to use for runner '" << runner.name << "'. (e.g. #ff00ff)\n";
getline(cin, clrAnswer);
runner.color = clrAnswer;
}
}
if (answer == "1 random")
{
cout << "Every RUNNER will have a random color.\n";
for (Runner& runner : runners)
runner.color = RandomColor();
}
if (answer == "2")
{
cout << "Please enter color to use for all runs. (e.g. #ff00ff)\n";
getline(cin, clrAnswer);
for (Runner& runner : runners)
runner.color = clrAnswer;
}
if (answer == "2 random")
{
cout << "Every RUN will have a random color.\n";
props.randomColors = true;
}
cout << "Please enter radius for circles (suggested: 10)\n";
getline(cin, answer);
props.circleRadius = atof(answer.c_str());
cout << "Please enter width for lines (suggested: 4)\n";
getline(cin, answer);
props.lineWidth = atof(answer.c_str());
cout << "Please enter X scale (normal is 1)\n";
getline(cin, answer);
props.xScale = atof(answer.c_str());
cout << "Please enter Y scale (normal is 1)\n";
getline(cin, answer);
props.yScale = atof(answer.c_str());
cout << "Starting writing to " << file_without_extension << ".cfg\n";
writingFile << "<?xml version=\"1.0\" encoding=\"UTF - 8\" standalone=\"no\"?>\n";
writingFile << "<svg width = \"" << props.width * props.xScale << "mm\" height = \"" << props.height * props.yScale << "mm\" viewBox = \"0 0 " << props.width * props.xScale << " " << props.height * props.yScale << "\" version = \"1.1\" id = \"svg1\" > \n";
for (Category& category : categories)
{
writingFile << "<g inkscape:groupmode=\"layer\" id=\"" << category.name << "\">\n";
string color;
if (props.randomColors)
color = RandomColor();
else
color = GetRunnerColor(runners, category.runs[0].name);
string name = category.runs[0].name;
double days = category.runs[0].days;
double time = category.runs[0].time;
writingFile << "<circle style = \"fill:" << color << "\" id = \"" << name << "\" cx = \"" << days * props.xScale << "\" cy = \"" << (time - props.lowestTime) * props.yScale << "\" r = \"" << props.circleRadius << "\"/>\n";
for (int i = 1; i < category.runs.size(); i++)
{
Run &run = category.runs[i];
writingFile << "<path style = \"stroke-width:" << props.lineWidth << ";stroke:" << color << ";stroke-opacity:1\" d = \"M "
<< days * props.xScale << "," << (time - props.lowestTime) * props.yScale << " "
<< run.days * props.xScale << "," << (run.time - props.lowestTime) * props.yScale << "\" id = \"" << name << "\"/>\n";
color;
if (props.randomColors)
color = RandomColor();
else
color = GetRunnerColor(runners, run.name);
name = run.name;
days = run.days;
time = run.time;
writingFile << "<circle style = \"fill:" << color << "\" id = \"" << name << "\" cx = \"" << run.days * props.xScale << "\" cy = \"" << (run.time - props.lowestTime) * props.yScale << "\" r = \"" << props.circleRadius << "\"/>\n";
}
writingFile << "</g>\n";
}
writingFile << "</svg>\n";
cout << "Finished writing to " << file_without_extension << ".cfg\n";
writingFile.close();
ReadFile.close();
cout << "Done. Press ENTER or the X button to close.\n";
cin.get();
}