Initial support for reverse-geocoding for Poland - data about powiaty.

sql-rework
Tomasz Golinski 2020-04-03 02:23:16 +02:00
rodzic 0727ad0b17
commit 7d9e978543
39 zmienionych plików z 12171 dodań i 1 usunięć

Wyświetl plik

@ -91,4 +91,6 @@ run `meson build; cd build; ninja`. You might need to set `CXX` variable to poin
* Maps of Voivodeships of Poland come from https://commons.wikimedia.org/wiki/File:Podlaskie_Voivodeship_location_map.svg, https://commons.wikimedia.org/wiki/File:Pomeranian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Kuyavian-Pomeranian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Warmian-Masurian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Masovian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Lesser_Poland_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Greater_Poland_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Opole_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Lower_Silesian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Silesian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Lublin_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Subcarpathian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:West_Pomeranian_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:%C5%9Awi%C4%99tokrzyskie_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:Lubusz_Voivodeship_location_map.svg, https://pl.wikipedia.org/wiki/Plik:%C5%81%C3%B3d%C5%BA_Voivodeship_location_map.svg and are licensed under CC-BY-SA.
* Data about administrative boundaries of Poland comes from OpenStreetMap via https://wambachers-osm.website/boundaries/.
* CSS tricks used to render histograms are based on https://css-tricks.com/making-charts-with-css.

Wyświetl plik

@ -64,6 +64,7 @@ public:
bool recommended = 0; // was the cache recommended by that user?
std::string type;
std::string region;
std::string subregion;
std::string origin;
std::string owner;
std::string owner_uuid;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,32 @@
configure_file(input: 'dolnoslaskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'dolnoslaskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'gornoslaskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'gornoslaskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'kujawsko-pomorskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'kujawsko-pomorskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'lodzkie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'lodzkie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'lubelskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'lubelskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'lubuskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'lubuskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'malopolskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'malopolskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'mazowieckie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'mazowieckie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'opolskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'opolskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'podkarpackie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'podkarpackie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'podlaskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'podlaskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'pomorskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'pomorskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'swietokrzyskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'swietokrzyskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'warminsko-mazurskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'warminsko-mazurskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'wielkopolskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'wielkopolskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'zachodniopomorskie.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
configure_file(input: 'zachodniopomorskie_sub.geojson', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -5,6 +5,7 @@
#include "heat.h"
#include "ocdb.h"
#include "common.h"
#include "region.h"
#include <iostream>
#include <iomanip>
@ -243,6 +244,26 @@ int main(int argc, char** argv) {
std::exit(EXIT_FAILURE);
}
// Prepare a set of regions
Country poland({
"dolnoslaskie",
"gornoslaskie",
"kujawsko-pomorskie",
"lodzkie",
"lubelskie",
"lubuskie",
"malopolskie",
"mazowieckie",
"opolskie",
"podkarpackie",
"podlaskie",
"pomorskie",
"swietokrzyskie",
"warminsko-mazurskie",
"wielkopolskie",
"zachodniopomorskie"
});
// Prepare sorted list of caches, excluding moving caches
std::map<std::string, int> dates;
Date_Caches sorted_caches;
@ -259,6 +280,9 @@ int main(int argc, char** argv) {
i = cc.erase(i);
continue;
}
poland.locate(*i);
dates[i->date]++;
sorted_caches.insert({ i->date_t, &*i });
if (i->type != "Moving" && i->type != "Own" && (!get_not_found || !exclude_quiz || i->type != "Quiz")) {
@ -424,6 +448,7 @@ int main(int argc, char** argv) {
show_histogram(cc, &Cache::type, "Cache types", 1);
show_histogram(cc, &Cache::size, "Cache sizes", 1);
show_histogram(cc, &Cache::region, "Regions", 1);
show_histogram(cc, &Cache::subregion, "Subregions", 1);
show_histogram(cc, &Cache::day_of_week, "Days of the week", 1, 0);
show_histogram(cc, &Cache::mon, "Months", 1, 0);
show_histogram(cc, &Cache::year, "Years", 1, 0);

Wyświetl plik

@ -14,7 +14,7 @@ if not magick_dep.found()
endif
link = ['-lgpx', '-lheatmap']
src = ['geostat.cpp', 'okapi.cpp', 'cache.cpp', 'debug.cpp', 'heat.cpp', 'ocdb.cpp', 'common.cpp']
src = ['geostat.cpp', 'okapi.cpp', 'cache.cpp', 'debug.cpp', 'heat.cpp', 'ocdb.cpp', 'common.cpp', 'region.cpp']
src_cli = ['geostat_cli.cpp', 'okapi.cpp', 'gpx.cpp', 'cache.cpp', 'debug.cpp', 'heat.cpp', 'ocdb.cpp', 'common.cpp']
src_db = ['geodb.cpp', 'debug.cpp', 'ocdb.cpp', 'okapi.cpp', 'cache.cpp', 'common.cpp']
@ -26,3 +26,4 @@ configure_file(input: 'rating-star.png', output: '@PLAINNAME@', copy: true, inst
configure_file(input: 'geo.css', output: '@PLAINNAME@', copy: true, install: true, install_dir: '.')
subdir('maps')
subdir('geojson')

112
region.cpp 100644
Wyświetl plik

@ -0,0 +1,112 @@
#include "region.h"
#include "debug.h"
#include <fstream>
#include <stdexcept>
#include <algorithm>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
typedef bg::model::point<double, 2, bg::cs::cartesian> 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) {
return (p.lat >= a.lat && p.lat <= b.lat && p.lon >= a.lon && p.lon <= b.lon);
}
bool ContourData::within(Position p) {
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<std::string, ContourData*> 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 name;
std::map<std::string, ContourData*> rr;
for (auto& el : j["features"].items()) {
std::cout << "X";
if (el.value()["properties"]["alltags"].count("short_name") > 0)
name = el.value()["properties"]["alltags"]["short_name"];
else if (el.value()["properties"].count("name") > 0)
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 " << name;
rr[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;
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<std::filesystem::path>& 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) {
Position p = c.pos;
for (auto& el : regions) {
if (el->within(p)) {
c.region = el->get_name();
c.subregion = el->find_subregion(p);
Debug(3) << "Found subregion " << c.subregion;
return;
}
}
}

58
region.h 100644
Wyświetl plik

@ -0,0 +1,58 @@
#pragma once
#include "cache.h"
#include <map>
#include <string>
#include <filesystem>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
namespace bg = boost::geometry;
class BoundingBox {
private:
Position a;
Position b;
public:
inline bool within(Position p);
BoundingBox(Position p1, Position p2);
};
class ContourData {
private:
bg::model::polygon<boost::geometry::model::d2::point_xy<double>> contour;
BoundingBox bbox;
public:
ContourData(BoundingBox bbox);
bool within(Position p);
void add_point(Position p);
};
class Region {
private:
ContourData* contour;
std::string name;
std::vector<Region*> subregions;
std::map<std::string, ContourData*> parse_geojson(const std::string& json_file);
public:
Region(ContourData* contour, std::string name) : contour(contour), name(name) {}
Region(const std::filesystem::path& geojson, const std::filesystem::path& geojson_sub);
~Region();
bool within(Position p) { return contour->within(p); }
std::string get_name() { return name; }
std::string find_subregion(Position p);
};
class Country {
private:
std::vector<Region*> regions;
public:
Country(const std::vector<std::filesystem::path>& jsons);
void locate(Cache& c);
};