summaryrefslogtreecommitdiffstats
path: root/divesitehelpers.cpp
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2015-07-01 12:36:21 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2015-07-02 06:50:49 -0700
commitb42bae2ce8b665c45020f53ef8b494dffc086d38 (patch)
tree742c51c27e315a29250a77538b4f2ecb25b4afb2 /divesitehelpers.cpp
parent3055f4ac2212fef67a6e191538fe615f48be7042 (diff)
downloadsubsurface-b42bae2ce8b665c45020f53ef8b494dffc086d38.tar.gz
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>
Diffstat (limited to 'divesitehelpers.cpp')
-rw-r--r--divesitehelpers.cpp121
1 files changed, 101 insertions, 20 deletions
diff --git a/divesitehelpers.cpp b/divesitehelpers.cpp
index 62b48ba94..4cc40f203 100644
--- a/divesitehelpers.cpp
+++ b/divesitehelpers.cpp
@@ -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;