mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Geo taxonomy: download the taxonomy data from geonames.org
There are a number of web servies we could use. All have their drawbacks. This one is free with free data. It's daily limits are reasonably high. For many coordinates I tested the results were good, for others at least not terrible. We can always consider supporting multiple such services. But for now this seems like a reasonable choice. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
3055f4ac22
commit
b42bae2ce8
2 changed files with 102 additions and 20 deletions
|
@ -41,54 +41,135 @@ void ReverseGeoLookupThread::run() {
|
||||||
|
|
||||||
QNetworkRequest request;
|
QNetworkRequest request;
|
||||||
QNetworkAccessManager *rgl = new QNetworkAccessManager();
|
QNetworkAccessManager *rgl = new QNetworkAccessManager();
|
||||||
|
QEventLoop loop;
|
||||||
|
QString mapquestURL("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3");
|
||||||
|
QString geonamesURL("http://api.geonames.org/findNearbyPlaceNameJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh");
|
||||||
|
QString geonamesOceanURL("http://api.geonames.org/oceanJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh");
|
||||||
|
QString divelogsURL("https://www.divelogs.de/mapsearch_divespotnames.php?lat=%1&lng=%2&radius=50");
|
||||||
|
QTimer timer;
|
||||||
|
|
||||||
request.setRawHeader("Accept", "text/json");
|
request.setRawHeader("Accept", "text/json");
|
||||||
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
|
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
|
||||||
QEventLoop loop;
|
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||||
QString apiCall("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3");
|
|
||||||
Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) {
|
Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) {
|
||||||
request.setUrl(apiCall.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
|
struct dive_site *ds = get_dive_site_by_uuid(info.uuid);
|
||||||
|
|
||||||
|
// first check the findNearbyPlaces API from geonames - that should give us country, state, city
|
||||||
|
request.setUrl(geonamesURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
|
||||||
|
|
||||||
QNetworkReply *reply = rgl->get(request);
|
QNetworkReply *reply = rgl->get(request);
|
||||||
QTimer timer;
|
|
||||||
timer.setSingleShot(true);
|
timer.setSingleShot(true);
|
||||||
|
|
||||||
QEventLoop loop;
|
|
||||||
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
|
||||||
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
timer.start(500); // 30 secs. timeout
|
timer.start(5000); // 5 secs. timeout
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
if(timer.isActive()) {
|
if(timer.isActive()) {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
if(reply->error() > 0)
|
if(reply->error() > 0) {
|
||||||
|
report_error("got error accessing geonames.org: %s", reply->errorString());
|
||||||
goto clear_reply;
|
goto clear_reply;
|
||||||
|
}
|
||||||
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
if (v < 200 || v >= 300)
|
if (v < 200 || v >= 300)
|
||||||
goto clear_reply;
|
goto clear_reply;
|
||||||
|
QByteArray fullReply = reply->readAll();
|
||||||
QJsonParseError errorObject;
|
QJsonParseError errorObject;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &errorObject);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject);
|
||||||
if (errorObject.error != QJsonParseError::NoError)
|
if (errorObject.error != QJsonParseError::NoError) {
|
||||||
|
report_error("error parsing geonames.org response: %s", errorObject.errorString());
|
||||||
goto clear_reply;
|
goto clear_reply;
|
||||||
|
}
|
||||||
QJsonObject obj = jsonDoc.object();
|
QJsonObject obj = jsonDoc.object();
|
||||||
QJsonObject address = obj.value("address").toObject();
|
QVariant geoNamesObject = obj.value("geonames").toVariant();
|
||||||
|
QVariantList geoNames = geoNamesObject.toList();
|
||||||
struct dive_site *ds = get_dive_site_by_uuid(info.uuid);
|
if (geoNames.count() > 0) {
|
||||||
ds->notes = add_to_string(ds->notes, "countrytag: %s", address.value("country").toString().toUtf8().data());
|
QVariantMap firstData = geoNames.at(0).toMap();
|
||||||
|
int ri = 0;
|
||||||
|
if (ds->taxonomy.category == NULL)
|
||||||
|
ds->taxonomy.category = alloc_taxonomy();
|
||||||
|
// get all the data - OCEAN is special, so start at COUNTRY
|
||||||
|
for (int j = COUNTRY; j < NR_CATEGORIES; j++) {
|
||||||
|
if (firstData[taxonomy_api_names[j]].isValid()) {
|
||||||
|
ds->taxonomy.category[ri].category = j;
|
||||||
|
ds->taxonomy.category[ri].origin = taxonomy::GEOCODED;
|
||||||
|
free((void*)ds->taxonomy.category[ri].value);
|
||||||
|
ds->taxonomy.category[ri].value = copy_string(qPrintable(firstData[taxonomy_api_names[j]].toString()));
|
||||||
|
ri++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ds->taxonomy.nr = ri;
|
||||||
|
mark_divelist_changed(true);
|
||||||
|
} else {
|
||||||
|
report_error("geonames.org did not provide reverse lookup information");
|
||||||
|
qDebug() << "no reverse geo lookup; geonames returned\n" << fullReply;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
report_error("timeout accessing geonames.org");
|
||||||
|
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
|
reply->abort();
|
||||||
|
}
|
||||||
|
// next check the oceans API to figure out the body of water
|
||||||
|
request.setUrl(geonamesOceanURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
|
||||||
|
reply = rgl->get(request);
|
||||||
|
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
|
timer.start(5000); // 5 secs. timeout
|
||||||
|
loop.exec();
|
||||||
|
if(timer.isActive()) {
|
||||||
|
timer.stop();
|
||||||
|
if(reply->error() > 0) {
|
||||||
|
report_error("got error accessing oceans API of geonames.org: %s", reply->errorString());
|
||||||
|
goto clear_reply;
|
||||||
|
}
|
||||||
|
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
if (v < 200 || v >= 300)
|
||||||
|
goto clear_reply;
|
||||||
|
QByteArray fullReply = reply->readAll();
|
||||||
|
QJsonParseError errorObject;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject);
|
||||||
|
if (errorObject.error != QJsonParseError::NoError) {
|
||||||
|
report_error("error parsing geonames.org response: %s", errorObject.errorString());
|
||||||
|
goto clear_reply;
|
||||||
|
}
|
||||||
|
QJsonObject obj = jsonDoc.object();
|
||||||
|
QVariant oceanObject = obj.value("ocean").toVariant();
|
||||||
|
QVariantMap oceanName = oceanObject.toMap();
|
||||||
|
if (oceanName["name"].isValid()) {
|
||||||
|
if (ds->taxonomy.category == NULL)
|
||||||
|
ds->taxonomy.category = alloc_taxonomy();
|
||||||
|
ds->taxonomy.category[ds->taxonomy.nr].category = OCEAN;
|
||||||
|
qDebug() << "set category of slot" << ds->taxonomy.nr << "to OCEAN(1)";
|
||||||
|
ds->taxonomy.category[ds->taxonomy.nr].origin = taxonomy::GEOCODED;
|
||||||
|
ds->taxonomy.category[ds->taxonomy.nr].value = copy_string(qPrintable(oceanName["name"].toString()));
|
||||||
|
ds->taxonomy.nr++;
|
||||||
|
mark_divelist_changed(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
report_error("timeout accessing geonames.org");
|
||||||
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
reply->abort();
|
reply->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_reply:
|
clear_reply:
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
rgl->deleteLater();
|
rgl->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReverseGeoLookupThread::lookup(dive_site *ds)
|
||||||
|
{
|
||||||
|
if (!ds)
|
||||||
|
return;
|
||||||
|
GeoLookupInfo info;
|
||||||
|
info.lat = ds->latitude;
|
||||||
|
info.lon = ds->longitude;
|
||||||
|
info.uuid = ds->uuid;
|
||||||
|
|
||||||
|
geo_lookup_data.clear();
|
||||||
|
geo_lookup_data.append(info);
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void add_geo_information_for_lookup(degrees_t latitude, degrees_t longitude, uint32_t uuid) {
|
extern "C" void add_geo_information_for_lookup(degrees_t latitude, degrees_t longitude, uint32_t uuid) {
|
||||||
GeoLookupInfo info;
|
GeoLookupInfo info;
|
||||||
info.lat = latitude;
|
info.lat = latitude;
|
||||||
|
|
|
@ -8,6 +8,7 @@ class ReverseGeoLookupThread : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
static ReverseGeoLookupThread *instance();
|
static ReverseGeoLookupThread *instance();
|
||||||
|
void lookup(struct dive_site *ds);
|
||||||
void run() Q_DECL_OVERRIDE;
|
void run() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Reference in a new issue