Skip to content

Commit 68dd4c5

Browse files
committed
Separate geocode and time zone functions
1 parent 6fa6da1 commit 68dd4c5

File tree

4 files changed

+152
-154
lines changed

4 files changed

+152
-154
lines changed

src/geotools.cpp

Lines changed: 120 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -316,169 +316,165 @@ bool GeoTools::GeocodeGoogle(const wxString& address, double* lat, double* lon,
316316
}
317317

318318
// Geocode using NREL Developer API (MapQuest) for NREL builds of SAM
319-
// submit address and no lat/lon to get lat/lon and optional time zone
320-
// submit no address and lat/lon to get time zone
321-
bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lon, double* tz, bool showprogress) {
319+
// submit address and no lat/lon to get lat/lon
320+
bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lon, bool showprogress) {
322321
wxBusyCursor _curs;
323322

324323
bool success = false;
325324

326-
if (!address.IsEmpty()) {
327-
328-
wxString plusaddr, url, webapi_string, str;
329-
plusaddr = url = webapi_string, str = "";
330-
wxEasyCurl curl;
331-
wxBusyCursor curs;
332-
rapidjson::GenericDocument < rapidjson::UTF16<> > reader; // change from UTF8 to UTF16 encoding to address unicode characters per SAM issue 1848
333-
rapidjson::ParseResult ok;
334-
335-
plusaddr = address;
336-
plusaddr.Replace(", ", "+");
337-
plusaddr.Replace(",", "+");
338-
plusaddr.Replace(" ", " ");
339-
plusaddr.Replace(" ", " ");
340-
plusaddr.Replace(" ", "+");
341-
342-
webapi_string = SamApp::WebApi("nrel_geocode_api");
343-
344-
if (webapi_string == "debug-mock-api")
345-
url = address;
346-
else {
347-
url = SamApp::WebApi("nrel_geocode_api") + "&location=" + plusaddr;
348-
url.Replace("<GEOCODEAPIKEY>", wxString(geocode_api_key));
349-
}
325+
wxString plusaddr, url, webapi_string, str;
326+
plusaddr = url = webapi_string, str = "";
327+
wxEasyCurl curl;
328+
wxBusyCursor curs;
329+
rapidjson::GenericDocument < rapidjson::UTF16<> > reader; // change from UTF8 to UTF16 encoding to address unicode characters per SAM issue 1848
330+
rapidjson::ParseResult ok;
350331

351-
// SAM issue 1968
352-
curl.AddHttpHeader("Content-Type: application/json");
353-
curl.AddHttpHeader("Accept: application/json");
332+
plusaddr = address;
333+
plusaddr.Replace(", ", "+");
334+
plusaddr.Replace(",", "+");
335+
plusaddr.Replace(" ", " ");
336+
plusaddr.Replace(" ", " ");
337+
plusaddr.Replace(" ", "+");
354338

355-
if (showprogress) {
356-
if (!curl.Get(url, "Geocoding address '" + address + "'..."))
357-
return false;
358-
}
359-
else {
360-
if (!curl.Get(url))
361-
return false;
362-
}
339+
webapi_string = SamApp::WebApi("nrel_geocode_api");
363340

364-
str = curl.GetDataAsString();
365-
ok = reader.Parse(str.c_str());
366-
if (!reader.HasParseError()) {
367-
if (reader.HasMember(L"results")) {
368-
if (reader[L"results"].IsArray()) {
369-
if (reader[L"results"][0].HasMember(L"locations")) {
370-
if (reader[L"results"][0][L"locations"].IsArray()) {
371-
if (reader[L"results"][0][L"locations"][0].HasMember(L"latLng")) {
372-
if (reader[L"results"][0][L"locations"][0][L"latLng"].HasMember(L"lat")) {
373-
if (reader[L"results"][0][L"locations"][0][L"latLng"][L"lat"].IsNumber()) {
374-
*lat = reader[L"results"][0][L"locations"][0][L"latLng"][L"lat"].GetDouble();
375-
if (reader[L"results"][0][L"locations"][0][L"latLng"].HasMember(L"lng")) {
376-
if (reader[L"results"][0][L"locations"][0][L"latLng"][L"lng"].IsNumber()) {
377-
*lon = reader[L"results"][0][L"locations"][0][L"latLng"][L"lng"].GetDouble();
378-
success = true; // only if lat and lon are numbers
379-
}
380-
}
341+
if (webapi_string == "debug-mock-api")
342+
url = address;
343+
else {
344+
url = SamApp::WebApi("nrel_geocode_api") + "&location=" + plusaddr;
345+
url.Replace("<GEOCODEAPIKEY>", wxString(geocode_api_key));
346+
}
347+
348+
// SAM issue 1968
349+
curl.AddHttpHeader("Content-Type: application/json");
350+
curl.AddHttpHeader("Accept: application/json");
381351

352+
if (showprogress) {
353+
if (!curl.Get(url, "Geocoding address '" + address + "'..."))
354+
return false;
355+
}
356+
else {
357+
if (!curl.Get(url))
358+
return false;
359+
}
360+
361+
str = curl.GetDataAsString();
362+
ok = reader.Parse(str.c_str());
363+
if (!reader.HasParseError()) {
364+
if (reader.HasMember(L"results")) {
365+
if (reader[L"results"].IsArray()) {
366+
if (reader[L"results"][0].HasMember(L"locations")) {
367+
if (reader[L"results"][0][L"locations"].IsArray()) {
368+
if (reader[L"results"][0][L"locations"][0].HasMember(L"latLng")) {
369+
if (reader[L"results"][0][L"locations"][0][L"latLng"].HasMember(L"lat")) {
370+
if (reader[L"results"][0][L"locations"][0][L"latLng"][L"lat"].IsNumber()) {
371+
*lat = reader[L"results"][0][L"locations"][0][L"latLng"][L"lat"].GetDouble();
372+
if (reader[L"results"][0][L"locations"][0][L"latLng"].HasMember(L"lng")) {
373+
if (reader[L"results"][0][L"locations"][0][L"latLng"][L"lng"].IsNumber()) {
374+
*lon = reader[L"results"][0][L"locations"][0][L"latLng"][L"lng"].GetDouble();
375+
success = true; // only if lat and lon are numbers
376+
}
382377
}
378+
383379
}
384380
}
385381
}
386382
}
387383
}
388384
}
389-
// check status code
390-
success = false;//overrides success of retrieving data
391-
392-
// cpg to do check this
393-
if (reader.HasMember(L"info")) {
394-
if (reader[L"info"].HasMember(L"statuscode")) {
395-
if (reader[L"info"][L"statuscode"].IsInt()) {
396-
success = reader[L"info"][L"statuscode"].GetInt() == 0;
397-
}
385+
}
386+
// check status code
387+
success = false;//overrides success of retrieving data
388+
389+
// cpg to do check this
390+
if (reader.HasMember(L"info")) {
391+
if (reader[L"info"].HasMember(L"statuscode")) {
392+
if (reader[L"info"][L"statuscode"].IsInt()) {
393+
success = reader[L"info"][L"statuscode"].GetInt() == 0;
398394
}
399395
}
400396
}
401-
else {
402-
wxMessageBox(rapidjson::GetParseError_En(ok.Code()), "geocode developer parse error ");
403-
}
404-
405-
if (!success)
406-
return false;
397+
}
398+
else {
399+
wxMessageBox(rapidjson::GetParseError_En(ok.Code()), "geocode developer parse error ");
407400
}
408401

409-
// time zone is optional
410-
// lat/lon may have been geocoded above or passed in as arguments
411-
if (tz != 0) // tz=0 if not passed as parameter
412-
{
413-
success = false;
402+
return success;
403+
}
414404

415-
wxString url, str;
416-
url = str = "";
417-
wxEasyCurl curl = wxEasyCurl();
418-
rapidjson::GenericDocument < rapidjson::UTF16<> > reader;
405+
// submit lat/lon to get tz
406+
bool GeoTools::GetTimeZone(double* lat, double* lon, double* tz, bool showprogress) {
407+
wxBusyCursor _curs;
419408

420-
// azure maps time zone api
421-
url = SamApp::WebApi("azure_maps_timezone_api");
422-
url.Replace("<LATLON>", wxString::Format("%.14lf,%.14lf", *lat, *lon));
423-
url.Replace("<AZUREAPIKEY>", wxString(azure_api_key));
409+
bool success = false;
424410

425-
curl.AddHttpHeader("Content-Type: application/json");
426-
curl.AddHttpHeader("Accept: application/json");
411+
wxString url, str;
412+
url = str = "";
413+
wxEasyCurl curl = wxEasyCurl();
414+
rapidjson::GenericDocument < rapidjson::UTF16<> > reader;
427415

428-
if (showprogress) {
429-
curl.Get(url, "Getting time zone '" + address + "'...");
430-
}
431-
else {
432-
curl.Get(url);
433-
}
416+
// azure maps time zone api
417+
url = SamApp::WebApi("azure_maps_timezone_api");
418+
url.Replace("<LATLON>", wxString::Format("%.14lf,%.14lf", *lat, *lon));
419+
url.Replace("<AZUREAPIKEY>", wxString(azure_api_key));
434420

435-
str = curl.GetDataAsString();
436-
reader.Parse(str.c_str());
437-
if (reader.HasMember(L"error")) {
438-
if (reader[L"error"].HasMember(L"code")) {
439-
if (reader[L"error"][L"code"].IsString()) {
440-
wxString error_str = reader[L"error"][L"code"].GetString();
441-
if (error_str.Lower() != "") {
442-
wxMessageBox(wxString::Format("Time Zone API Error!\n%s", error_str));
443-
return false;
444-
}
421+
curl.AddHttpHeader("Content-Type: application/json");
422+
curl.AddHttpHeader("Accept: application/json");
423+
424+
if (showprogress) {
425+
curl.Get(url, wxString::Format("Getting time zone for %g, %g.", *lat, *lon));
426+
}
427+
else {
428+
curl.Get(url);
429+
}
430+
431+
str = curl.GetDataAsString();
432+
reader.Parse(str.c_str());
433+
if (reader.HasMember(L"error")) {
434+
if (reader[L"error"].HasMember(L"code")) {
435+
if (reader[L"error"][L"code"].IsString()) {
436+
wxString error_str = reader[L"error"][L"code"].GetString();
437+
if (error_str.Lower() != "") {
438+
wxMessageBox(wxString::Format("Time Zone API Error!\n%s", error_str));
439+
return false;
445440
}
446441
}
447442
}
443+
}
448444

449-
*tz = NULL;
450-
if (!reader.HasParseError()) {
451-
if (reader.HasMember(L"TimeZones")) {
452-
if (reader[L"TimeZones"].IsArray()) {
453-
if (reader[L"TimeZones"][0].HasMember(L"ReferenceTime")) {
454-
if (reader[L"TimeZones"][0][L"ReferenceTime"].HasMember(L"StandardOffset")) {
455-
if (reader[L"TimeZones"][0][L"ReferenceTime"][L"StandardOffset"].IsString()) {
456-
wxString stz = reader[L"TimeZones"][0][L"ReferenceTime"][L"StandardOffset"].GetString();
457-
wxArrayString as = wxSplit(stz, ':');
458-
if (as.Count() != 3) return false; // example "-08:00:00"
459-
if (!as[0].ToDouble(tz)) return false;
460-
double offset = 0;
461-
if (as[1] == "30") offset = 0.5;
462-
if (*tz < 0)
463-
*tz = *tz - offset;
464-
else
465-
*tz = *tz + offset;
466-
success = true;
467-
}
445+
*tz = NULL;
446+
if (!reader.HasParseError()) {
447+
if (reader.HasMember(L"TimeZones")) {
448+
if (reader[L"TimeZones"].IsArray()) {
449+
if (reader[L"TimeZones"][0].HasMember(L"ReferenceTime")) {
450+
if (reader[L"TimeZones"][0][L"ReferenceTime"].HasMember(L"StandardOffset")) {
451+
if (reader[L"TimeZones"][0][L"ReferenceTime"][L"StandardOffset"].IsString()) {
452+
wxString stz = reader[L"TimeZones"][0][L"ReferenceTime"][L"StandardOffset"].GetString();
453+
wxArrayString as = wxSplit(stz, ':');
454+
if (as.Count() != 3) return false; // example "-08:00:00"
455+
if (!as[0].ToDouble(tz)) return false;
456+
double offset = 0;
457+
if (as[1] == "30") offset = 0.5;
458+
if (*tz < 0)
459+
*tz = *tz - offset;
460+
else
461+
*tz = *tz + offset;
462+
success = true;
468463
}
469464
}
470465
}
471466
}
472467
}
473-
else { // parse error
474-
wxMessageBox(wxString::Format("Time Zone API Error!\nFailed to parse response."));
475-
success = false;
476-
}
468+
}
469+
else { // parse error
470+
wxMessageBox(wxString::Format("Time Zone API Error!\nFailed to parse response."));
471+
success = false;
477472
}
478473

479474
return success;
480475
}
481476

477+
482478
wxBitmap GeoTools::StaticMap(double lat, double lon, int zoom, MapProvider service) {
483479

484480
rapidjson::GenericDocument < rapidjson::UTF16<> > reader;

src/geotools.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@ class GeoTools
4343
// Requires a Google Cloud Project account with billing enabled
4444
// This is an alternative to GeocodeDeveloper for non-NREL builds of SAM
4545
// Google API key is defined in private.h
46-
static bool GeocodeGoogle(const wxString& address,
47-
double* lat, double* lon, double* tz = 0, bool showprogress = true);
46+
static bool GeocodeGoogle(const wxString& address, double* lat, double* lon, double* tz = 0, bool showprogress = true);
4847

4948
// Use private NREL Developer API (MapQuest wrapper) to return lat/lon from address
5049
// Requires a special private API key from NREL defined in private.h
51-
static bool GeocodeDeveloper(const wxString& address,
52-
double* lat, double* lon, double* tz = 0, bool showprogress = true);
50+
static bool GeocodeDeveloper(const wxString& address, double* lat, double* lon, bool showprogress = true);
5351

52+
// Use Microsoft Azure API to return time zone from lat/lon
53+
// Azure Map API key is defined in private.h
54+
static bool GeoTools::GetTimeZone(double* lat, double* lon, double* tz, bool showprogress = true);
5455

5556
// Convert array of degrees, minutes, seconds to decimal degrees (DD)
5657
static bool dms_to_dd(double &d, double &m, double &s, double* dd);

src/invoke.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3133,7 +3133,7 @@ void fcall_windtoolkit(lk::invoke_t &cxt)
31333133
wxBusyInfo bid("Converting address to lat/lon.");
31343134

31353135
// use GeoTools::GeocodeGoogle for non-NREL builds and set google_api_key in private.h
3136-
if (!GeoTools::GeocodeDeveloper(spd.GetAddress(), &lat, &lon, NULL, false))
3136+
if (!GeoTools::GeocodeDeveloper(spd.GetAddress(), &lat, &lon, false))
31373137
{
31383138
wxMessageDialog* md = new wxMessageDialog(NULL, "Failed to convert address to lat/lon. This may be caused by a geocoding service outage or internet connection problem.", "WIND Toolkit Download Error", wxOK);
31393139
md->ShowModal();
@@ -3884,18 +3884,12 @@ void fcall_geocode(lk::invoke_t& cxt)
38843884

38853885
// use GeoTools::GeocodeGoogle for non-NREL builds and set google_api_key in private.h
38863886
if (is_address) {
3887-
if (get_tz) {
3888-
ok = GeoTools::GeocodeDeveloper(cxt.arg(0).as_string(), &lat, &lon, &tz);
3889-
cxt.result().hash_item("tz").assign(tz);
3890-
}
3891-
else {
3892-
ok = GeoTools::GeocodeDeveloper(cxt.arg(0).as_string(), &lat, &lon);
3893-
}
3887+
ok = GeoTools::GeocodeDeveloper(cxt.arg(0).as_string(), &lat, &lon);
38943888
if (!ok) {
38953889
err = wxString::Format("Call to geocoding API failed for address: %s", address);
38963890
}
38973891
}
3898-
else if (!address.IsEmpty()) { // if address is assume input string is lat/lon pair and try to parse
3892+
else if (!address.IsEmpty()) { // if address is empty assume input string is lat/lon pair and try to parse
38993893
wxString coordinates = cxt.arg(0).as_string();
39003894
wxString lat_str, lon_str;
39013895
ok = GeoTools::coordinates_to_lat_lon(coordinates, lat_str, lon_str);
@@ -3908,17 +3902,21 @@ void fcall_geocode(lk::invoke_t& cxt)
39083902
ok = GeoTools::coordinate_to_dms(lat_str, &lat_d, &lat_m, &lat_s) && GeoTools::coordinate_to_dms(lon_str, &lon_d, &lon_m, &lon_s);
39093903
if (ok) {
39103904
ok = GeoTools::dms_to_dd(lat_d, lat_m, lat_s, &lat) && GeoTools::dms_to_dd(lon_d, lon_m, lon_s, &lon);
3911-
if (ok && get_tz) {
3912-
// cpg TO DO passing "" as first argument is when we only need tz, consider separate GeoTools::GetTimeZone() function?
3913-
//ok = GeoTools::GeocodeDeveloper(cxt.arg(0).as_string(), &lat, &lon, &tz);
3914-
ok = GeoTools::GeocodeDeveloper("", &lat, &lon, &tz);
3915-
if (!ok) {
3916-
err = wxString::Format("Timezone not found for: (%g, %g)", lat, lon);
3917-
}
3905+
if (!ok) {
3906+
err = wxString::Format("Failed to parse latitude/longitude pair %s.", coordinates);
39183907
}
39193908
}
39203909
}
39213910
}
3911+
3912+
if (get_tz) {
3913+
ok = GeoTools::GetTimeZone(&lat, &lon, &tz);
3914+
if (!ok) {
3915+
err = wxString::Format("Timezone not found for: (%g, %g)", lat, lon);
3916+
}
3917+
cxt.result().hash_item("tz").assign(tz);
3918+
}
3919+
39223920

39233921
cxt.result().hash_item("lat").assign(lat);
39243922
cxt.result().hash_item("lon").assign(lon);

0 commit comments

Comments
 (0)