@@ -193,7 +193,6 @@ bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lo
193193 curl.AddHttpHeader (" Content-Type: application/json" );
194194 curl.AddHttpHeader (" Accept: application/json" );
195195
196-
197196 if (showprogress) {
198197 if (!curl.Get (url, " Geocoding address '" + address + " '..." ))
199198 return false ;
@@ -203,27 +202,12 @@ bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lo
203202 return false ;
204203 }
205204
206- // change from UTF8 to UTF16 encoding to address unicode characters per SAM GitHub issue 1848
205+ // change from UTF8 to UTF16 encoding to address unicode characters per SAM issue 1848
207206 rapidjson::GenericDocument < rapidjson::UTF16<> > reader;
208207 wxString str = curl.GetDataAsString ();
209208
210209 rapidjson::ParseResult ok = reader.Parse (str.c_str ());
211210
212-
213- /*
214- example for "denver, co"
215- {"info":
216- {"statuscode":0,"copyright":
217- {"text":"© 2024 MapQuest, Inc.","imageUrl":"http://api.mqcdn.com/res/mqlogo.gif","imageAltText":"© 2024 MapQuest, Inc."}
218- ,"messages":[]}
219- ,"options":{"maxResults":-1,"ignoreLatLngInput":false}
220- ,"results":
221- [{"providedLocation":{"location":"denver co"},"locations":
222- [{"street":"","adminArea6":"","adminArea6Type":"Neighborhood","adminArea5":"Denver","adminArea5Type":"City","adminArea4":"Denver","adminArea4Type":"County","adminArea3":"CO","adminArea3Type":"State","adminArea1":"US","adminArea1Type":"Country","postalCode":"","geocodeQualityCode":"A5XAX","geocodeQuality":"CITY","dragPoint":false,"sideOfStreet":"N","linkId":"0","unknownInput":"","type":"s","latLng":{"lat":39.74001,"lng":-104.99202},"displayLatLng":{"lat":39.74001,"lng":-104.99202},"mapUrl":""}]
223- }
224- ]}
225- */
226-
227211 if (!reader.HasParseError ()) {
228212 if (reader.HasMember (L" results" )) {
229213 if (reader[L" results" ].IsArray ()) {
@@ -233,21 +217,21 @@ bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lo
233217 if (reader[L" results" ][0 ][L" locations" ][0 ][L" latLng" ].HasMember (L" lat" )) {
234218 if (reader[L" results" ][0 ][L" locations" ][0 ][L" latLng" ][L" lat" ].IsNumber ()) {
235219 *lat = reader[L" results" ][0 ][L" locations" ][0 ][L" latLng" ][L" lat" ].GetDouble ();
236- success = true ;
237- }
238- }
239- if (reader[ L" results " ][ 0 ][ L" locations " ][ 0 ][ L" latLng " ]. HasMember ( L" lng " )) {
240- if (reader[ L" results " ][ 0 ][ L" locations " ][ 0 ][ L" latLng " ][ L" lng " ]. IsNumber ()) {
241- *lon = reader[ L" results " ][ 0 ][ L" locations " ][ 0 ][ L" latLng " ][ L" lng " ]. GetDouble ();
242- success &= true ;
220+ if (reader[ L" results " ][ 0 ][ L" locations " ][ 0 ][ L" latLng " ]. HasMember ( L" lng " )) {
221+ if (reader[ L" results " ][ 0 ][ L" locations " ][ 0 ][ L" latLng " ][ L" lng " ]. IsNumber ()) {
222+ *lon = reader[ L" results " ][ 0 ][ L" locations " ][ 0 ][ L" latLng " ][ L" lng " ]. GetDouble ();
223+ success = true ; // only if lat and lon are numbers
224+ }
225+ }
226+
243227 }
244228 }
245- }
229+ }
246230 }
247231 }
248232 }
249233 }
250- // check status code
234+ /* // check status code
251235 success = false;//overrides success of retrieving data
252236
253237 if (reader.HasMember(L"info")) {
@@ -257,6 +241,7 @@ bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lo
257241 }
258242 }
259243 }
244+ */
260245 }
261246 else {
262247 wxMessageBox (rapidjson::GetParseError_En (ok.Code ()), " geocode developer parse error " );
@@ -265,83 +250,86 @@ bool GeoTools::GeocodeDeveloper(const wxString& address, double* lat, double* lo
265250 if (!success)
266251 return false ;
267252
268-
269-
253+ // time zone is optional
270254 if (tz != 0 )
271255 {
272256 success = false ;
273257
274258 curl = wxEasyCurl ();
275259
276-
277-
278- url = SamApp::WebApi (" bing_maps_timezone_api" );
279- url.Replace (" <POINT>" , wxString::Format (" %.14lf,%.14lf" , *lat, *lon));
280- url.Replace (" <BINGAPIKEY>" , wxString (bing_api_key));
260+ // azure maps time zone api
261+ url = SamApp::WebApi (" azure_maps_timezone_api" );
262+ url.Replace (" <LATLON>" , wxString::Format (" %.14lf,%.14lf" , *lat, *lon));
263+ url.Replace (" <AZUREAPIKEY>" , wxString (azure_api_key));
281264
282265 curl.AddHttpHeader (" Content-Type: application/json" );
283266 curl.AddHttpHeader (" Accept: application/json" );
284267
285-
286- if (showprogress)
287- {
288- if (!curl.Get (url, " Geocoding address '" + address + " '..." ))
289- return false ;
268+ if (showprogress) {
269+ curl.Get (url, " Getting time zone '" + address + " '..." );
290270 }
291271 else {
292- if (!curl.Get (url))
293- return false ;
272+ curl.Get (url);
294273 }
295274
296275 str = curl.GetDataAsString ();
297276
298277 reader.Parse (str.c_str ());
299278
279+ if (reader.HasMember (L" error" )) {
280+ if (reader[L" error" ].HasMember (L" code" )) {
281+ if (reader[L" error" ][L" code" ].IsString ()) {
282+ wxString error_str = reader[L" error" ][L" code" ].GetString ();
283+ if (error_str.Lower () != " " ) {
284+ wxMessageBox (wxString::Format (" Time Zone API Error!\n %s" , error_str));
285+ return false ;
286+ }
287+ }
288+ }
289+ }
290+
291+ *tz = NULL ;
300292 if (!reader.HasParseError ()) {
301- if (reader.HasMember (L" resourceSets" )) {
302- if (reader[L" resourceSets" ].IsArray ()) {
303- if (reader[L" resourceSets" ][0 ].HasMember (L" resources" )) {
304- if (reader[L" resourceSets" ][0 ][L" resources" ].IsArray ()) {
305- if (reader[L" resourceSets" ][0 ][L" resources" ][0 ].HasMember (L" timeZone" )) {
306- if (reader[L" resourceSets" ][0 ][L" resources" ][0 ][L" timeZone" ].HasMember (L" utcOffset" )) {
307- if (reader[L" resourceSets" ][0 ][L" resources" ][0 ][L" timeZone" ][L" utcOffset" ].IsString ()) {
308- wxString stz = reader[L" resourceSets" ][0 ][L" resources" ][0 ][L" timeZone" ][L" utcOffset" ].GetString ();
309- wxArrayString as = wxSplit (stz, ' :' );
310- if (as.Count () != 2 ) return false ;
311- if (!as[0 ].ToDouble (tz)) return false ;
312- double offset = 0 ;
313- if (as[1 ] == " 30" ) offset = 0.5 ;
314- if (*tz < 0 )
315- *tz = *tz - offset;
316- else
317- *tz = *tz + offset;
318- success = true ;
319- }
320- }
293+ if (reader.HasMember (L" TimeZones" )) {
294+ if (reader[L" TimeZones" ].IsArray ()) {
295+ if (reader[L" TimeZones" ][0 ].HasMember (L" ReferenceTime" )) {
296+ if (reader[L" TimeZones" ][0 ][L" ReferenceTime" ].HasMember (L" StandardOffset" )) {
297+ if (reader[L" TimeZones" ][0 ][L" ReferenceTime" ][L" StandardOffset" ].IsString ()) {
298+ wxString stz = reader[L" TimeZones" ][0 ][L" ReferenceTime" ][L" StandardOffset" ].GetString ();
299+ wxArrayString as = wxSplit (stz, ' :' );
300+ if (as.Count () != 3 ) return false ; // example "-08:00:00"
301+ if (!as[0 ].ToDouble (tz)) return false ;
302+ double offset = 0 ;
303+ if (as[1 ] == " 30" ) offset = 0.5 ;
304+ if (*tz < 0 )
305+ *tz = *tz - offset;
306+ else
307+ *tz = *tz + offset;
308+ success = true ;
321309 }
322310 }
323311 }
324312 }
325313 }
326- // check status code
327- success = false ;// overrides success of retrieving data
328-
329- if (reader.HasMember (L" statusDescription" )) {
330- if (reader[L" statusDescription" ].IsString ()) {
331- wxString str = reader[L" statusDescription" ].GetString ();
332- success = str.Lower () == " ok" ;
333- }
334- }
335314 }
336-
315+ else { // parse error
316+ wxMessageBox (wxString::Format (" Time Zone API Error!\n Failed to parse response." ));
317+ success = false ;
318+ }
337319 }
338320 return success;
339- }
321+ }
340322
341323
342324wxBitmap GeoTools::StaticMap (double lat, double lon, int zoom, MapProvider service) {
343- if (zoom > 21 ) zoom = 21 ;
344- if (zoom < 1 ) zoom = 1 ;
325+
326+ rapidjson::GenericDocument < rapidjson::UTF16<> > reader;
327+ wxString str;
328+
329+ // Azure get static map documentation https://learn.microsoft.com/en-us/rest/api/maps/render/get-map-static-image
330+ // valid zoom range is 0-19 for tilesetId = microsoft.imagery
331+ if (zoom > 19 ) zoom = 21 ;
332+ if (zoom < 0 ) zoom = 0 ;
345333 wxString zoomStr = wxString::Format (" %d" , zoom);
346334
347335 wxString url;
@@ -353,13 +341,46 @@ wxBitmap GeoTools::StaticMap(double lat, double lon, int zoom, MapProvider servi
353341
354342 }
355343 else {
356- url = SamApp::WebApi (" bing_maps_imagery_api " );
344+ url = SamApp::WebApi (" azure_maps_static_map_api " );
357345 url.Replace (" <POINT>" , wxString::Format (" %.14lf,%.14lf" , lat, lon));
358346 url.Replace (" <ZOOMLEVEL>" , zoomStr);
359- url.Replace (" <BINGAPIKEY>" , wxString (bing_api_key));
347+ url.Replace (" <LONLAT>" , wxString::Format (" %.14lf,%.14lf" , lon, lat));
348+ url.Replace (" <AZUREAPIKEY>" , wxString (azure_api_key));
360349 }
361350
362351 wxEasyCurl curl;
352+
353+ curl.AddHttpHeader (" Accept: image/png" );
354+
363355 bool ok = curl.Get (url, " Obtaining aerial imagery..." );
364- return ok ? wxBitmap (curl.GetDataAsImage (wxBITMAP_TYPE_JPEG)) : wxNullBitmap;
356+
357+ str = curl.GetDataAsString ();
358+ reader.Parse (str.c_str ());
359+
360+ // curl Get failed
361+ if (!ok) {
362+ wxMessageBox (" Static Map Error!\n Failed to download static map." );
363+ return wxNullBitmap;
364+ }
365+
366+ str = curl.GetDataAsString ();
367+ // returned JSON string instead of image, probably an error message
368+ if (str != " " ) {
369+ reader.Parse (str.c_str ());
370+ if (reader.HasMember (L" error" )) {
371+ if (reader[L" error" ].HasMember (L" message" )) {
372+ if (reader[L" error" ][L" message" ].IsString ()) {
373+ wxMessageBox (wxString::Format (" Static Map Error!\n %s" , reader[L" error" ][L" message" ].GetString ()));
374+ return wxNullBitmap;
375+ }
376+ }
377+ wxMessageBox (wxString::Format (" Static Map Error!\n %s" , reader[L" error" ][L" code" ].GetString ()));
378+ return wxNullBitmap;
379+ }
380+ wxMessageBox (wxString::Format (" Static Map Error!\n No map image." ));
381+ return wxNullBitmap;
382+ }
383+ else {
384+ return ok ? wxBitmap (curl.GetDataAsImage (wxBITMAP_TYPE_PNG)) : wxNullBitmap;
385+ }
365386}
0 commit comments