#include "region.h" #include "debug.h" #include #include #include #include using json = nlohmann::json; typedef bg::model::point point_t; BoundingBox::BoundingBox(Position p1, Position p2) { a.lat = std::min(p1.lat, p2.lat); b.lat = std::max(p1.lat, p2.lat); a.lon = std::min(p1.lon, p2.lon); b.lon = std::max(p1.lon, p2.lon); } bool BoundingBox::within(Position p) const { return (p.lat >= a.lat && p.lat <= b.lat && p.lon >= a.lon && p.lon <= b.lon); } bool ContourData::within(Position p) const { return bbox.within(p) && bg::within(point_t{ p.lon, p.lat }, contour); } ContourData::ContourData(BoundingBox bbox) : bbox(bbox) {} void ContourData::add_point(Position p) { bg::append(contour, point_t{ p.lon, p.lat }); } // TODO: Parse inner ring and multi-poligon std::map Region::parse_geojson(const std::string& json_file) { if (!std::filesystem::exists(json_file)) { throw std::runtime_error("File " + json_file + " does not exist."); } std::ifstream file(json_file); json j; file >> j; std::string reg_name; std::map rr; for (auto& el : j["features"].items()) { if (el.value()["properties"]["alltags"].count("short_name") > 0) reg_name = el.value()["properties"]["alltags"]["short_name"]; else if (el.value()["properties"].count("localname") > 0) reg_name = el.value()["properties"]["localname"]; else if (el.value()["properties"].count("name") > 0) reg_name = el.value()["properties"]["name"]; else { Debug(1) << "Unknown name for an object, skipping"; continue; } ContourData* cont = new ContourData(BoundingBox(Position(el.value()["bbox"][1], el.value()["bbox"][0]), Position(el.value()["bbox"][3], el.value()["bbox"][2]))); for (auto& el2 : el.value()["geometry"]["coordinates"][0][0].items()) { cont->add_point(Position(el2.value()[1], el2.value()[0])); } Debug(3) << "Parsed region " << reg_name; rr[reg_name] = cont; } return rr; } Region::Region(const std::filesystem::path& geojson, const std::filesystem::path& geojson_sub) { auto reg = *parse_geojson(geojson).begin(); name = reg.first; contour = reg.second; auto geodata = parse_geojson(geojson_sub); std::transform(geodata.begin(), geodata.end(), std::back_inserter(subregions), [&](auto a) { return new Region(a.second, a.first); }); // for (auto& el : parse_geojson(geojson_sub)) // subregions.emplace_back(new Region(el.second, el.first)); } Region::~Region() { subregions.clear(); delete contour; } std::string Region::find_subregion(Position p) { if (!within(p)) throw std::runtime_error("Point not in this region."); auto res = std::find_if(subregions.begin(), subregions.end(), [&](auto a) { return a->within(p); }); if (res != subregions.end()) return (*res)->get_name(); return ""; // else // throw std::runtime_error("Point " + std::to_string(p.lat) + " " + std::to_string(p.lon) + " not in any of the subregions."); } Country::Country(const std::vector& jsons) { for (auto el : jsons) { std::filesystem::path p1 = "geojson" / el; std::filesystem::path p2 = p1; p1 += ".geojson"; p2 += "_sub.geojson"; regions.emplace_back(new Region(p1, p2)); } } void Country::locate(Cache& c) { auto el = std::find_if(regions.begin(), regions.end(), [&](auto a) { return a->within(c.pos); }); if (el != regions.end()) { c.region = (*el)->get_name(); c.subregion = (*el)->find_subregion(c.pos); Debug(3) << "Found subregion " << c.subregion; } }