diff --git a/README.md b/README.md index 30c20f9..812db8e 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Generate HTML stats from Opencaching data or GPX files. -s n stamp size for a heat map (default = 15) -e use exponential to flatten the heat map -t draw trail instead of heat map + -a draw animated map instead of heat map -m map chosen map: Poland, Poland_relief, Poland_big, Europe, World or a name of voivodeship (default = Poland) -h display this help screen ``` diff --git a/geostat.cpp b/geostat.cpp index 166319e..242317c 100644 --- a/geostat.cpp +++ b/geostat.cpp @@ -36,6 +36,7 @@ void show_usage() { 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-h\t\tdisplay this help screen\n"; std::exit(EXIT_FAILURE); @@ -47,6 +48,7 @@ int main(int argc, char** argv) { std::string heat_map = "Poland"; bool heat_exp = 0; bool trail = 0; + bool anim = 0; bool use_oc = 0; bool use_ocpl_db = 0; bool get_not_found = 0; @@ -86,7 +88,7 @@ int main(int argc, char** argv) { if (argc == 1) show_usage(); int o; - while ((o = getopt(argc, argv, "qNOQD:o::p:d:u:n:r:k:i:f:H:s:m:eth?")) != -1) + while ((o = getopt(argc, argv, "qNOQD:o::p:d:u:n:r:k:i:f:H:s:m:etah?")) != -1) switch (o) { case 'D': Debug::set_debug_level(get_num('d', optarg)); @@ -158,6 +160,9 @@ int main(int argc, char** argv) { case 't': trail = 1; break; + case 'a': + anim = 1; + break; case 'h': case '?': default: @@ -180,6 +185,12 @@ int main(int argc, char** argv) { std::exit(EXIT_FAILURE); } } + + if (trail && anim) { + std::cout << "Options \"-a\" and \"-t\" are mutually exclusive.\n"; + std::exit(EXIT_FAILURE); + } + if (use_oc) { if (!ocpl_user_uuid.empty() || !ocpl_user.empty()) { Okapi OCpl(ocpl_url, ocpl_key); @@ -240,6 +251,8 @@ int main(int argc, char** argv) { } if (get_not_found) { Caches tmp = db.get_user_caches_not_found(ocpl_user_uuid); + Okapi OCpl(ocpl_url, ocpl_key); + OCpl.update_caches(tmp); std::copy(tmp.begin(), tmp.end(), std::back_inserter(cc)); region_count = db.get_region_stats(); } else if (get_owned) { @@ -319,7 +332,7 @@ int main(int argc, char** argv) { std::sort(caches_by_rating.begin(), caches_by_rating.end(), [&](const Cache* a, const Cache* b) { return a->rating > b->rating; }); } else { for (auto& i : cc) { - if (i.type != "Moving" && i.type != "Own" && (!exclude_quiz || i.type != "Quiz")) { + if (i.type != "Moving" && i.type != "Own" && (!exclude_quiz || i.type != "Quiz") && i.rating >= 4.9) { fcc.push_back(&i); poland.locate(i); } @@ -364,7 +377,9 @@ int main(int argc, char** argv) { std::exit(EXIT_FAILURE); } hmap.generate_path(heat_file, sorted_fcaches); - } else + } else if (anim) + hmap.generate_anim(heat_file, sorted_caches, 2); + else hmap.generate(heat_file, fcc, heat_stamp_size, (heat_exp == 1 ? "exp" : "soft")); std::cout << "
\n\"heat\n
\n"; } diff --git a/geostat_cli.cpp b/geostat_cli.cpp index a00d055..cbd12ab 100644 --- a/geostat_cli.cpp +++ b/geostat_cli.cpp @@ -34,6 +34,7 @@ void show_usage() { 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"; @@ -56,6 +57,7 @@ int main(int argc, char** argv) { std::string heat_map = "Poland"; bool heat_exp = 0; bool trail = 0; + bool anim = 0; bool use_oc = 0; bool use_ocpl_db = 0; bool get_not_found = 0; @@ -84,7 +86,7 @@ int main(int argc, char** argv) { if (argc == 1) show_usage(); int o; - while ((o = getopt(argc, argv, "qNOg:o::p:d:u:n:r:k:MDCH:s:m:etLTYh?")) != -1) + 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)); @@ -160,6 +162,9 @@ int main(int argc, char** argv) { case 't': trail = 1; break; + case 'a': + anim = 1; + break; case 'L': show_list = 1; break; @@ -188,6 +193,11 @@ int main(int argc, char** argv) { } } + if (trail && anim) { + std::cout << "Options \"-a\" and \"-t\" are mutually exclusive.\n"; + std::exit(EXIT_FAILURE); + } + if (use_oc) { if (!ocpl_user_uuid.empty() || !ocpl_user.empty()) { Okapi OCpl(ocpl_url, ocpl_key); @@ -311,6 +321,8 @@ int main(int argc, char** argv) { Heat hmap(chosen_map); if (trail) hmap.generate_path(heat_file, sorted_caches); + else if (anim) + hmap.generate_anim(heat_file, sorted_caches, 2); else hmap.generate(heat_file, fcc, heat_stamp_size, (heat_exp == 1 ? "exp" : "soft")); } diff --git a/heat.cpp b/heat.cpp index a849c89..cf64275 100644 --- a/heat.cpp +++ b/heat.cpp @@ -76,3 +76,34 @@ void Heat::generate_path(const std::string& filename, const Date_Caches& sorted) contour.draw(draw); contour.write(filename); } + +void Heat::generate_anim(const std::string& filename, const Date_Caches& sorted, int dot_size) { + std::vector frames; + frames.emplace_back(MAPS_DIR / mp->map_file); + + Magick::Image canvas(Magick::Geometry(mp->size_x, mp->size_y), "transparent"); + canvas.strokeWidth(1); + canvas.gifDisposeMethod(1); + canvas.animationDelay(1); + canvas.animationIterations(1); + + const Cache* prev = nullptr; + + for (auto el = sorted.begin()++; el != sorted.end(); el++) { + if (mp->contains(Position(el->second->pos.lat, el->second->pos.lon))) { + canvas.erase(); + if (prev) { + canvas.strokeColor("black"); + canvas.fillColor("black"); + canvas.draw(Magick::DrawableEllipse(mp->coordinate_x(Position(prev->pos.lat, prev->pos.lon)), mp->coordinate_y(Position(prev->pos.lat, prev->pos.lon)), dot_size, dot_size, 0, 360)); + } + prev = el->second; + canvas.strokeColor("red"); + canvas.fillColor("red"); + canvas.draw(Magick::DrawableEllipse(mp->coordinate_x(Position(prev->pos.lat, prev->pos.lon)), mp->coordinate_y(Position(prev->pos.lat, prev->pos.lon)), dot_size, dot_size, 0, 360)); + frames.push_back(canvas); + } + } + + Magick::writeImages(frames.begin(), frames.end(), filename); +} diff --git a/heat.h b/heat.h index 75fee4e..0e1508b 100644 --- a/heat.h +++ b/heat.h @@ -15,4 +15,5 @@ public: void generate(const std::string& filename, const pCaches& points, int stamp_size, const std::string& theme = "soft"); void generate_path(const std::string& filename, const Date_Caches& sorted); + void generate_anim(const std::string& filename, const Date_Caches& sorted, int dot_size); };