#include "user.h" #include "debug.h" #include "heat.h" #include "common.h" #include #include #include #include void show_usage() { std::cout << "Usage: geostat [options]\n"; std::cout << "Generate stats from Opencaching data or GPX files.\n\n"; std::cout << " * Data sources:\n"; std::cout << "\t-o[user]\tuse Opencaching; if specified user will be a user name used for all OC instances\n"; std::cout << "\t-p user\t\tuser for opencaching.pl\n"; std::cout << "\t-d user\t\tuser for opencaching.de\n"; std::cout << "\t-u user\t\tuser for opencaching.us\n"; std::cout << "\t-n user\t\tuser for opencaching.nl\n"; std::cout << "\t-r user\t\tuser for opencaching.ro\n"; std::cout << "\t-k user\t\tuser for opencaching.uk\n"; std::cout << "\t-g file\t\tuse specified gpx file\n"; std::cout << "\t-q\t\tuse local SQLite file with dump of OC database\n"; std::cout << " * Output:\n"; std::cout << "\t-N\t\tcompute stats only for unfound caches (works only with SQLite)\n"; std::cout << "\t-M\t\tprint geographically extreme caches\n"; // std::cout << "\t-D\t\tprint furthest and closest caches\n"; std::cout << "\t-C\t\tprint calendar related stats\n"; std::cout << "\t-H file\t\trender a heat map to a file\n"; std::cout << "\t-s n\t\tstamp size for a heat map (default = 15)\n"; std::cout << "\t-e\t\tuse exponential to flatten the heat map\n"; std::cout << "\t-t\t\tdraw trail instead of heat map\n"; std::cout << "\t-a\t\tdraw animated map instead of heat map\n"; std::cout << "\t-m map\t\tchosen map: Poland, Poland_relief, Poland_big, Europe, World or a name of voivodeship (default = Poland)\n"; std::cout << "\t-L\t\tprint all caches\n"; std::cout << "\t-T\t\tprint D/T matrix\n"; std::cout << "\t-O\t\tprint owner count for found caches\n"; std::cout << "\t-Y\t\tprint types count for found caches\n"; std::cout << "\t-h\t\tdisplay this help screen\n"; std::exit(EXIT_FAILURE); } int main(int argc, char** argv) { User user; bool show_minmax = 0; // bool show_dist = 0; bool show_list = 0; bool show_dt = 0; bool show_owners = 0; bool show_types = 0; bool show_calendar = 0; std::string heat_file; int heat_stamp_size = 15; std::string heat_map = "Poland"; bool heat_exp = 0; bool trail = 0; bool anim = 0; std::string gpx_file; #include "config_user.h" if (argc == 1) show_usage(); int o; while ((o = getopt(argc, argv, "qNOg:o::p:d:u:n:r:k:MDCH:s:m:etaLTYh?")) != -1) switch (o) { // case 'd': // Debug::set_debug_level(get_num('d',optarg)); // break; // case 'g': // gpx_file = optarg; break; case 'o': user.use_oc = 1; if (optarg) { user.ocpl_user = optarg; user.ocde_user = optarg; user.ocus_user = optarg; user.ocnl_user = optarg; user.ocro_user = optarg; user.ocuk_user = optarg; } break; case 'p': user.ocpl_user = optarg; break; case 'd': user.ocde_user = optarg; break; case 'u': user.ocus_user = optarg; break; case 'n': user.ocnl_user = optarg; break; case 'r': user.ocro_user = optarg; break; case 'k': user.ocuk_user = optarg; break; case 'q': user.use_ocdb = 1; break; case 'N': user.get_not_found = 1; break; case 'O': user.get_owned = 1; break; case 'M': show_minmax = 1; break; // case 'D': // show_dist = 1; // break; case 'C': show_calendar = 1; break; // case 'O': // show_owners = 1; // break; case 'Y': show_types = 1; break; case 'H': heat_file = optarg; break; case 's': heat_stamp_size = get_num('s', optarg); break; case 'm': heat_map = optarg; break; case 'e': heat_exp = 1; break; case 't': trail = 1; break; case 'a': anim = 1; break; case 'L': show_list = 1; break; case 'T': show_dt = 1; break; case 'h': case '?': default: show_usage(); } if (user.get_not_found || user.get_owned) { user.use_oc = 0; user.use_ocdb = 1; // trail = 0; if (user.ocpl_user_uuid.empty() && user.ocpl_user.empty() && user.ocde_user_uuid.empty() && user.ocde_user.empty()) { std::cout << "Options \"-N\" or \"-O\" work only with OCpl or OCde.\n"; std::exit(EXIT_FAILURE); } if (user.get_not_found && user.get_owned) { std::cout << "Options \"-N\" and \"-O\" are mutually exclusive.\n"; std::exit(EXIT_FAILURE); } } if (trail && anim) { std::cout << "Options \"-a\" and \"-t\" are mutually exclusive.\n"; std::exit(EXIT_FAILURE); } user.get_caches(); if (user.caches_count == 0) { std::cout << "No caches found, aborting.\n"; std::exit(EXIT_FAILURE); } user.prepare_lists_of_caches(); if (!heat_file.empty()) { const Map* chosen_map; if (maps.count(heat_map) > 0) chosen_map = &maps.at(heat_map); else { std::cout << "Map " << heat_map << " not found.\n"; std::exit(EXIT_FAILURE); } Heat hmap(chosen_map); if (trail) hmap.generate_path(heat_file, user.sorted_caches); else if (anim) hmap.generate_anim(heat_file, user.sorted_caches, heat_stamp_size); else hmap.generate(heat_file, user.fcc, heat_stamp_size, (heat_exp == 1 ? "exp" : "soft")); } if (!user.get_not_found) { if (show_list) { for (auto el : user.sorted_caches) el.second->show(); } if (show_minmax) { auto N = *std::max_element(user.fcc.begin(), user.fcc.end(), [&](const Cache* a, const Cache* b) { return a->pos.lat < b->pos.lat; }); auto S = *std::min_element(user.fcc.begin(), user.fcc.end(), [&](const Cache* a, const Cache* b) { return a->pos.lat < b->pos.lat; }); auto E = *std::max_element(user.fcc.begin(), user.fcc.end(), [&](const Cache* a, const Cache* b) { return a->pos.lon < b->pos.lon; }); auto W = *std::min_element(user.fcc.begin(), user.fcc.end(), [&](const Cache* a, const Cache* b) { return a->pos.lon < b->pos.lon; }); 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(user.fcc.begin(), user.fcc.end(), [&](const Cache* a, const Cache* b) { return a->distance() < b->distance(); }); // auto near = *std::min_element(user.fcc.begin(), user.fcc.end(), [&](const Cache* a, const Cache* b) { return a->distance() < b->distance(); }); // // std::cout << "Nearest cache: " << near->distance() << " km\n"; // near->show(); // std::cout << "Furthest cache: " << far->distance() << " km\n"; // far->show(); // } if (show_owners) { show_histogram(user.cc, &Cache::owner, "Cache owners"); } if (show_types) { show_histogram(user.cc, &Cache::type, "Cache types"); show_histogram(user.cc, &Cache::size, "Cache sizes"); show_histogram(user.cc, &Cache::origin, "Services"); show_histogram(user.cc, &Cache::region, "Regions"); } if (show_calendar) { show_histogram(user.cc, &Cache::day_of_week, "Days of the week", 0, 0); show_histogram(user.cc, &Cache::mon, "Months", 0, 0); show_histogram(user.cc, &Cache::year, "Years", 0, 0); } 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(user.cc.begin(), user.cc.end(), [i, j](const 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'; } } } else { if (show_list) { for (const auto& el : user.cc) el.show(); } } }