mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-17 20:16:16 +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;
|
||||
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("User-Agent", getUserAgent().toUtf8());
|
||||
QEventLoop loop;
|
||||
QString apiCall("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3");
|
||||
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
|
||||
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);
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
|
||||
QEventLoop loop;
|
||||
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
timer.start(500); // 30 secs. timeout
|
||||
timer.start(5000); // 5 secs. timeout
|
||||
loop.exec();
|
||||
|
||||
if(timer.isActive()) {
|
||||
timer.stop();
|
||||
if(reply->error() > 0)
|
||||
if(reply->error() > 0) {
|
||||
report_error("got error accessing 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(reply->readAll(), &errorObject);
|
||||
if (errorObject.error != QJsonParseError::NoError)
|
||||
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();
|
||||
QJsonObject address = obj.value("address").toObject();
|
||||
|
||||
struct dive_site *ds = get_dive_site_by_uuid(info.uuid);
|
||||
ds->notes = add_to_string(ds->notes, "countrytag: %s", address.value("country").toString().toUtf8().data());
|
||||
|
||||
QVariant geoNamesObject = obj.value("geonames").toVariant();
|
||||
QVariantList geoNames = geoNamesObject.toList();
|
||||
if (geoNames.count() > 0) {
|
||||
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 {
|
||||
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()));
|
||||
reply->abort();
|
||||
}
|
||||
|
||||
clear_reply:
|
||||
clear_reply:
|
||||
reply->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) {
|
||||
GeoLookupInfo info;
|
||||
info.lat = latitude;
|
||||
|
|
|
@ -8,6 +8,7 @@ class ReverseGeoLookupThread : public QThread {
|
|||
Q_OBJECT
|
||||
public:
|
||||
static ReverseGeoLookupThread *instance();
|
||||
void lookup(struct dive_site *ds);
|
||||
void run() Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Reference in a new issue