2019-09-08 16:42:10 +00:00
|
|
|
#include "okapi.h"
|
|
|
|
#include "gpx.h"
|
|
|
|
#include "cache.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "heat.h"
|
2019-10-04 00:30:17 +00:00
|
|
|
#include "ocdb.h"
|
2019-09-08 16:42:10 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <unistd.h>
|
2019-09-11 17:48:03 +00:00
|
|
|
#include <map>
|
|
|
|
|
2019-09-23 20:04:23 +00:00
|
|
|
void show_histogram(Caches* cc, std::string Cache::*ptr) {
|
2019-09-11 17:48:03 +00:00
|
|
|
std::map<std::string, int> histogram;
|
|
|
|
std::vector<std::pair<std::string, int>> pairs;
|
|
|
|
for (auto el : *cc)
|
|
|
|
histogram[el.*ptr]++;
|
|
|
|
for (auto el : histogram)
|
|
|
|
pairs.push_back(el);
|
|
|
|
sort(pairs.begin(), pairs.end(), [=](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.second > b.second; });
|
|
|
|
|
|
|
|
for (auto own : pairs)
|
|
|
|
std::cout << own.first << ": " << own.second << '\n';
|
|
|
|
}
|
2019-09-08 16:42:10 +00:00
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
bool show_minmax = 0;
|
|
|
|
bool show_dist = 0;
|
|
|
|
bool show_list = 0;
|
|
|
|
bool show_dt = 0;
|
2019-09-11 17:48:03 +00:00
|
|
|
bool show_owners = 0;
|
|
|
|
bool show_types = 0;
|
2019-09-08 16:42:10 +00:00
|
|
|
std::string heat_file;
|
|
|
|
int heat_stamp_size = 15;
|
2019-09-08 20:18:13 +00:00
|
|
|
std::string heat_map;
|
2019-09-12 12:07:46 +00:00
|
|
|
bool heat_exp = 0;
|
2019-09-08 16:42:10 +00:00
|
|
|
bool use_ocpl = 0;
|
2019-10-04 00:30:17 +00:00
|
|
|
bool use_ocpl_db = 0;
|
|
|
|
bool get_not_found = 0;
|
2019-09-08 16:42:10 +00:00
|
|
|
std::string ocpl_user;
|
|
|
|
std::string ocpl_url = "https://opencaching.pl/okapi/";
|
2019-10-04 00:30:17 +00:00
|
|
|
const std::string Database = "ocpl.sqlite";
|
2019-09-08 16:42:10 +00:00
|
|
|
std::string gpx_file;
|
|
|
|
|
|
|
|
#include "config_user.h"
|
|
|
|
|
|
|
|
int o;
|
2019-10-04 00:30:17 +00:00
|
|
|
while ((o = getopt(argc, argv, "qng:d:pu:MDOH:s:m:eLTYh?")) != -1)
|
2019-09-08 16:42:10 +00:00
|
|
|
switch (o) {
|
|
|
|
case 'd':
|
|
|
|
try {
|
|
|
|
if (std::stoi(optarg) > 0) {
|
|
|
|
// Debug(1) << "Setting debug level to " << optarg;
|
|
|
|
Debug::set_debug_level(std::stoi(optarg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
std::cout << "Option \"-d\" requires a valid number as an argument\n";
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
gpx_file = optarg;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
use_ocpl = 1;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
ocpl_user = optarg;
|
|
|
|
break;
|
2019-10-04 00:30:17 +00:00
|
|
|
case 'q':
|
|
|
|
use_ocpl_db = 1;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
get_not_found = 1;
|
|
|
|
break;
|
2019-09-08 16:42:10 +00:00
|
|
|
case 'M':
|
|
|
|
show_minmax = 1;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
show_dist = 1;
|
|
|
|
break;
|
2019-09-11 17:48:03 +00:00
|
|
|
case 'O':
|
|
|
|
show_owners = 1;
|
|
|
|
break;
|
|
|
|
case 'Y':
|
|
|
|
show_types = 1;
|
|
|
|
break;
|
2019-09-08 16:42:10 +00:00
|
|
|
case 'H':
|
|
|
|
heat_file = optarg;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
try {
|
|
|
|
if (std::stoi(optarg) > 0) {
|
|
|
|
heat_stamp_size = std::stoi(optarg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
std::cout << "Option \"-s\" requires a valid number as an argument\n";
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
break;
|
2019-09-08 20:18:13 +00:00
|
|
|
case 'm':
|
|
|
|
heat_map = optarg;
|
2019-09-08 16:42:10 +00:00
|
|
|
break;
|
2019-09-12 12:07:46 +00:00
|
|
|
case 'e':
|
|
|
|
heat_exp = 1;
|
|
|
|
break;
|
2019-09-08 16:42:10 +00:00
|
|
|
case 'L':
|
|
|
|
show_list = 1;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
show_dt = 1;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
default:
|
2019-10-04 00:30:17 +00:00
|
|
|
std::cout << "Usage: [-p] [-g file] [-qn] [-MDHLTOYh] [-s size] [-m map]\n";
|
2019-09-08 16:42:10 +00:00
|
|
|
std::cout << "Generate stats from Opencaching data or GPX files.\n\n";
|
|
|
|
std::cout << " * Data source:\n";
|
|
|
|
std::cout << "\t-p\tuse Opencaching.pl\n";
|
|
|
|
std::cout << "\t-u user\tuser for Opencaching\n";
|
|
|
|
std::cout << "\t-g file\tuse specified gpx file\n";
|
2019-10-04 00:30:17 +00:00
|
|
|
std::cout << "\t-q\tuse local SQLite file\n";
|
|
|
|
std::cout << "\t-n\tget only unfound caches (works only with SQLite)\n";
|
2019-09-08 16:42:10 +00:00
|
|
|
std::cout << " * Output:\n";
|
|
|
|
std::cout << "\t-M\tprint geographically extreme caches\n";
|
|
|
|
std::cout << "\t-D\tprint furthest and closest caches\n";
|
|
|
|
std::cout << "\t-H file\trender a heat map to a file\n";
|
|
|
|
std::cout << "\t-s n\tstamp size for a heat map (default = 15)\n";
|
2019-09-24 12:47:49 +00:00
|
|
|
std::cout << "\t-e\tuse exponential to flatten the heat map\n";
|
2019-09-24 12:52:10 +00:00
|
|
|
std::cout << "\t-m map\tchosen map: Poland, Poland_relief, Poland_big, Europe or a name of voivodeship (default = Poland)\n";
|
2019-09-08 16:42:10 +00:00
|
|
|
std::cout << "\t-L\tprint all caches\n";
|
|
|
|
std::cout << "\t-T\tprint D/T matrix\n";
|
2019-09-11 17:48:03 +00:00
|
|
|
std::cout << "\t-O\tprint owner count for found caches\n";
|
|
|
|
std::cout << "\t-Y\tprint types count for found caches\n";
|
2019-09-08 16:42:10 +00:00
|
|
|
std::cout << "\t-h\tdisplay this help screen\n";
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
Caches cc;
|
|
|
|
|
|
|
|
if (use_ocpl) {
|
|
|
|
Okapi OCpl(ocpl_url, ocpl_key);
|
|
|
|
if (!ocpl_user.empty()) {
|
|
|
|
ocpl_user_uuid = OCpl.get_uuid(ocpl_user);
|
|
|
|
}
|
|
|
|
cc.merge(OCpl.get_user_caches(ocpl_user_uuid, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gpx_file.empty()) {
|
|
|
|
GPX gpxfile(gpx_file);
|
|
|
|
cc.merge(gpxfile.get_user_caches());
|
|
|
|
}
|
|
|
|
|
2019-10-04 00:30:17 +00:00
|
|
|
if (use_ocpl_db) {
|
|
|
|
OCdb db(Database);
|
|
|
|
Okapi OCpl(ocpl_url, ocpl_key);
|
|
|
|
if (!ocpl_user.empty()) {
|
|
|
|
ocpl_user_uuid = OCpl.get_uuid(ocpl_user);
|
|
|
|
}
|
|
|
|
if (get_not_found) {
|
|
|
|
cc.merge(db.get_user_caches_not_found(ocpl_user_uuid));
|
|
|
|
} else {
|
|
|
|
cc.merge(db.get_user_caches(ocpl_user_uuid, 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-08 16:42:10 +00:00
|
|
|
// TODO: some cache deduplication is needed
|
|
|
|
|
|
|
|
Debug(2) << "Caches read: " << cc.size() << '\n';
|
|
|
|
|
|
|
|
if (!heat_file.empty()) {
|
2019-09-08 20:18:13 +00:00
|
|
|
const Map* chosen_map;
|
2019-09-15 10:34:10 +00:00
|
|
|
if (maps.count(heat_map) > 0)
|
|
|
|
chosen_map = &maps.at(heat_map);
|
2019-09-08 20:18:13 +00:00
|
|
|
else {
|
|
|
|
std::cout << "Map " << heat_map << " not found.\n";
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
Heat hmap(&cc, chosen_map);
|
2019-09-12 12:07:46 +00:00
|
|
|
hmap.generate(heat_file, heat_stamp_size, (heat_exp == 1 ? "exp" : "soft"));
|
2019-09-08 16:42:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (show_minmax) {
|
|
|
|
auto N = std::max_element(cc.begin(), cc.end(), CacheCmpNS);
|
|
|
|
auto S = std::min_element(cc.begin(), cc.end(), CacheCmpNS);
|
|
|
|
auto E = std::max_element(cc.begin(), cc.end(), CacheCmpEW);
|
|
|
|
auto W = std::min_element(cc.begin(), cc.end(), CacheCmpEW);
|
|
|
|
|
|
|
|
std::cout << "Most N:\n";
|
|
|
|
N->show();
|
|
|
|
std::cout << "Most S:\n";
|
|
|
|
S->show();
|
|
|
|
std::cout << "Most E:\n";
|
|
|
|
E->show();
|
|
|
|
std::cout << "Most W:\n";
|
|
|
|
W->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (show_dist) {
|
|
|
|
auto far = std::max_element(cc.begin(), cc.end(), CacheCmpDist);
|
|
|
|
auto near = std::min_element(cc.begin(), cc.end(), CacheCmpDist);
|
|
|
|
|
|
|
|
std::cout << "Nearest cache: " << near->distance() << " km\n";
|
|
|
|
near->show();
|
|
|
|
std::cout << "Furthest cache: " << far->distance() << " km\n";
|
|
|
|
far->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (show_list) {
|
|
|
|
for (auto el : cc)
|
|
|
|
el.show();
|
|
|
|
}
|
|
|
|
|
2019-09-11 17:48:03 +00:00
|
|
|
if (show_owners) {
|
|
|
|
std::cout << "Owners:\n";
|
|
|
|
show_histogram(&cc, &Cache::owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (show_types) {
|
|
|
|
std::cout << "Types:\n";
|
|
|
|
show_histogram(&cc, &Cache::type);
|
|
|
|
|
2019-09-12 11:58:54 +00:00
|
|
|
std::cout << "\nServices:\n";
|
2019-09-11 17:48:03 +00:00
|
|
|
show_histogram(&cc, &Cache::origin);
|
2019-09-12 11:58:54 +00:00
|
|
|
|
|
|
|
std::cout << "\nRegions:\n";
|
|
|
|
show_histogram(&cc, &Cache::region);
|
2019-09-11 17:48:03 +00:00
|
|
|
}
|
|
|
|
|
2019-09-08 16:42:10 +00:00
|
|
|
if (show_dt) {
|
|
|
|
short dt_table[11][11];
|
|
|
|
|
|
|
|
std::cout << std::setw(5) << "D\\T";
|
|
|
|
for (int j = 2; j <= 10; j++) { // print table terr headers
|
|
|
|
std::cout << std::setw(5) << j / 2.0;
|
|
|
|
}
|
|
|
|
std::cout << '\n';
|
|
|
|
|
|
|
|
for (int i = 2; i <= 10; i++) { // i -> diff in rows
|
|
|
|
std::cout << std::setw(5) << i / 2.0;
|
|
|
|
for (int j = 2; j <= 10; j++) { // j -> terr in cols
|
|
|
|
dt_table[i][j] = std::count_if(cc.begin(), cc.end(), [i, j](Cache c) { return (c.diff == i / 2.0 && c.terr == j / 2.0); });
|
|
|
|
std::cout << std::setw(5) << dt_table[i][j];
|
|
|
|
}
|
|
|
|
std::cout << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|