GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/webapis_geomaps.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 95 109 87.2%
Functions: 12 12 100.0%
Branches: 13 26 50.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/tech/webapis.h"
30 #include "gate/results.h"
31 #include "gate/geopositions.h"
32 #include "gate/encode/json.h"
33 #include "gate/utilities.h"
34 #include "gate/mathematics.h"
35
36 #define GATE_WEBAPIS_GEOMAPS_REQUEST_NAME GATE_STRUCT_WEBAPIS_NAME("geomaps_request")
37 static gate_struct_item_t const geomaps_request_members[] =
38 {
39 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_STRING, provider, "provider", GATE_STRUCT_FLAG_DEFAULT),
40 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_UI32, image_width, "image_width", GATE_STRUCT_FLAG_DEFAULT),
41 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_UI32, image_height, "image_height", GATE_STRUCT_FLAG_DEFAULT),
42 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_R32, center_latitude, "center_latitude", GATE_STRUCT_FLAG_DEFAULT),
43 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_R32, center_longitude, "center_longitude", GATE_STRUCT_FLAG_DEFAULT),
44 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_R32, radius_meters, "radius_meters", GATE_STRUCT_FLAG_DEFAULT),
45 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_request_t, GATE_TYPE_I16, image_type, "image_type", GATE_STRUCT_FLAG_DEFAULT),
46 };
47 static gate_struct_descriptor_t const geomaps_request_descriptor =
48 GATE_STRUCT_DESCRIPTOR(gate_tech_webapi_geomaps_request_t, GATE_WEBAPIS_GEOMAPS_REQUEST_NAME, geomaps_request_members);
49
50 1 void gate_tech_webapi_geomaps_request_init(gate_tech_webapi_geomaps_request_t* request)
51 {
52 1 gate_mem_clear(request, sizeof(gate_tech_webapi_geomaps_request_t));
53 1 request->struct_base.struct_descriptor = &geomaps_request_descriptor;
54 1 }
55
56
57
58 #define GATE_WEBAPIS_GEOMAPS_RESPONSE_NAME GATE_STRUCT_WEBAPIS_NAME("geomaps_response")
59 static gate_struct_item_t const geomaps_response_members[] =
60 {
61 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_UI32, image_width, "image_width", GATE_STRUCT_FLAG_DEFAULT),
62 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_UI32, image_height, "image_height", GATE_STRUCT_FLAG_DEFAULT),
63 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, center_latitude, "center_latitude", GATE_STRUCT_FLAG_DEFAULT),
64 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, center_longitude, "center_longitude", GATE_STRUCT_FLAG_DEFAULT),
65 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, min_latitude, "min_latitude", GATE_STRUCT_FLAG_DEFAULT),
66 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, min_longitude, "min_longitude", GATE_STRUCT_FLAG_DEFAULT),
67 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, max_latitude, "max_latitude", GATE_STRUCT_FLAG_DEFAULT),
68 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, max_longitude, "max_longitude", GATE_STRUCT_FLAG_DEFAULT),
69 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, width_meters, "width_meters", GATE_STRUCT_FLAG_DEFAULT),
70 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_R32, height_meters, "height_meters", GATE_STRUCT_FLAG_DEFAULT),
71 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_I16, image_type, "image_type", GATE_STRUCT_FLAG_DEFAULT),
72 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_I16, image_format, "image_format", GATE_STRUCT_FLAG_DEFAULT),
73 GATE_STRUCT_ITEM_EX(gate_tech_webapi_geomaps_response_t, GATE_TYPE_I16, image_data, "image_data", GATE_STRUCT_FLAG_DEFAULT),
74 };
75 static gate_struct_descriptor_t const geomaps_response_descriptor =
76 GATE_STRUCT_DESCRIPTOR(gate_tech_webapi_geomaps_response_t, GATE_WEBAPIS_GEOMAPS_RESPONSE_NAME, geomaps_response_members);
77
78 1 void gate_tech_webapi_geomaps_response_init(gate_tech_webapi_geomaps_response_t* response)
79 {
80 1 gate_mem_clear(response, sizeof(gate_tech_webapi_geomaps_response_t));
81 1 response->struct_base.struct_descriptor = &geomaps_response_descriptor;
82 1 }
83
84 /*
85
86 // old implementation for BingMaps, service shutdown in 2025 //
87
88 static gate_real32_t extract_real_item(gate_property_t const* prop_arr, gate_size_t ndx)
89 {
90 gate_property_t const* prop = gate_property_array_get(prop_arr, ndx);
91 gate_string_t str = GATE_STRING_INIT_EMPTY;
92 gate_real64_t r = 0.0;
93 gate_property_typeid_t proptype;
94 gate_result_t result;
95 if (NULL != prop)
96 {
97 proptype = gate_property_get_type(prop);
98 if (proptype == GATE_PROPERTY_TYPE_STRING)
99 {
100 result = gate_property_get_string(prop, &str);
101 if (GATE_SUCCEEDED(result))
102 {
103 gate_string_parse_real(&str, &r);
104 }
105 }
106 else
107 {
108 gate_property_get_real(prop, &r);
109 }
110 }
111 gate_string_release(&str);
112 return (gate_real32_t)r;
113 }
114
115 static gate_uint32_t extract_str_ui32_member(gate_property_t const* prop_arr, gate_string_t const* name)
116 {
117 gate_property_t const* prop = gate_property_member_get(prop_arr, name);
118 gate_string_t str = GATE_STRING_INIT_EMPTY;
119 gate_int64_t i = 0;
120 gate_result_t result;
121 if (NULL != prop)
122 {
123 result = gate_property_get_string(prop, &str);
124 if (GATE_SUCCEEDED(result))
125 {
126 gate_string_parse_int(&str, &i);
127 }
128 }
129 gate_string_release(&str);
130 return (gate_uint32_t)i;
131 }
132
133 #define BREAK_IF_NULL(varname) if(NULL == varname) { break; }
134
135 static gate_result_t extract_properties(gate_property_t const* prop, gate_tech_webapi_geomaps_response_t* response)
136 {
137 static gate_string_t const propname_resourceSets = GATE_STRING_INIT_STATIC("resourceSets");
138 static gate_string_t const propname_resources = GATE_STRING_INIT_STATIC("resources");
139 static gate_string_t const propname_bbox = GATE_STRING_INIT_STATIC("bbox");
140 static gate_string_t const propname_mapCenter = GATE_STRING_INIT_STATIC("mapCenter");
141 static gate_string_t const propname_coordinates = GATE_STRING_INIT_STATIC("coordinates");
142 static gate_string_t const propname_imageWidth = GATE_STRING_INIT_STATIC("imageWidth");
143 static gate_string_t const propname_imageHeight = GATE_STRING_INIT_STATIC("imageHeight");
144 gate_property_t const* resource_sets = NULL;
145 gate_property_t const* resource_set0 = NULL;
146 gate_property_t const* resources = NULL;
147 gate_property_t const* resource = NULL;
148 gate_property_t const* bbox = NULL;
149 gate_property_t const* center = NULL;
150 gate_property_t const* coords = NULL;
151 gate_result_t ret = GATE_RESULT_INVALIDCONTENT;
152
153 do
154 {
155 resource_sets = gate_property_member_get(prop, &propname_resourceSets);
156 BREAK_IF_NULL(resource_sets);
157 resource_set0 = gate_property_array_get(resource_sets, 0);
158 BREAK_IF_NULL(resource_set0);
159 resources = gate_property_member_get(resource_set0, &propname_resources);
160 BREAK_IF_NULL(resources);
161 resource = gate_property_array_get(resources, 0);
162 BREAK_IF_NULL(resource);
163 bbox = gate_property_member_get(resource, &propname_bbox);
164 BREAK_IF_NULL(bbox);
165 center = gate_property_member_get(resource, &propname_mapCenter);
166 BREAK_IF_NULL(center);
167 coords = gate_property_member_get(center, &propname_coordinates);
168 BREAK_IF_NULL(coords);
169
170 response->image_width = extract_str_ui32_member(resource, &propname_imageWidth);
171 response->image_height = extract_str_ui32_member(resource, &propname_imageHeight);
172
173 response->min_latitude = extract_real_item(bbox, 0);
174 response->min_longitude = extract_real_item(bbox, 1);
175 response->max_latitude = extract_real_item(bbox, 2);
176 response->max_longitude = extract_real_item(bbox, 3);
177
178 response->center_latitude = extract_real_item(coords, 0);
179 response->center_longitude = extract_real_item(coords, 1);
180 ret = GATE_RESULT_OK;
181
182 } while (0);
183
184 return ret;
185
186 }
187
188 static void create_bing_query(gate_strbuilder_t* query_builder,
189 gate_real32_t minlat, gate_real32_t minlong, gate_real32_t maxlat, gate_real32_t maxlong,
190 gate_uint32_t width, gate_uint32_t height, gate_bool_t as_metadata, gate_bool_t pngimage, gate_string_t const* apikey)
191 {
192 gate_strbuilder_append_cstr(query_builder, "?mapArea=");
193 gate_strbuilder_append_real(query_builder, minlat, 0, 6, 0);
194 gate_strbuilder_append_cstr(query_builder, ",");
195 gate_strbuilder_append_real(query_builder, minlong, 0, 6, 0);
196 gate_strbuilder_append_cstr(query_builder, ",");
197 gate_strbuilder_append_real(query_builder, maxlat, 0, 6, 0);
198 gate_strbuilder_append_cstr(query_builder, ",");
199 gate_strbuilder_append_real(query_builder, maxlong, 0, 6, 0);
200 gate_strbuilder_append_cstr(query_builder, "&mapSize=");
201 gate_strbuilder_append_int32(query_builder, width);
202 gate_strbuilder_append_cstr(query_builder, ",");
203 gate_strbuilder_append_int32(query_builder, height);
204 if (as_metadata)
205 {
206 gate_strbuilder_append_cstr(query_builder, "&mapMetadata=1");
207 }
208 else
209 {
210 if (pngimage)
211 {
212 gate_strbuilder_append_cstr(query_builder, "&format=png");
213 }
214 }
215 gate_strbuilder_append_cstr(query_builder, "&key=");
216 gate_strbuilder_append_string(query_builder, apikey);
217 }
218
219 #define BING_MAP_BASE_URL "http://dev.virtualearth.net/REST/V1/Imagery/Map/"
220 static gate_string_t const bing_road_url = GATE_STRING_INIT_STATIC(BING_MAP_BASE_URL "road");
221 static gate_string_t const bing_aerial_url = GATE_STRING_INIT_STATIC(BING_MAP_BASE_URL "aerial");
222 static gate_string_t const bing_aerialwithlabels_url = GATE_STRING_INIT_STATIC(BING_MAP_BASE_URL "aerialwithlabels");
223 static gate_string_t const bing_apikey = GATE_STRING_INIT_STATIC("MvLhnePhoOakkLRadvjE~DqbqTh8gUgq5MFown4hTHQ~AvoZiHcNoG8i8wJxC5vjA36KWU0qJiwqAuL3ZWy9vYKcGuQvDrPFiGqwAX3BUqC6");
224
225
226 static gate_result_t bing_load_map_info(gate_tech_webapi_context_t* context,
227 gate_tech_webapi_geomaps_request_t* request,
228 gate_tech_webapi_geomaps_response_t* response)
229 {
230 const gate_real32_t mplat = (gate_real32_t)gate_geopos_meters_per_latitude(request->center_latitude);
231 const gate_real32_t mplon = (gate_real32_t)gate_geopos_meters_per_longitude(request->center_latitude);
232 const gate_real32_t minlat = request->center_latitude - request->radius_meters / mplat;
233 const gate_real32_t minlong = request->center_longitude - request->radius_meters / mplon;
234 const gate_real32_t maxlat = request->center_latitude + request->radius_meters / mplat;
235 const gate_real32_t maxlong = request->center_longitude + request->radius_meters / mplon;
236
237 gate_result_t ret = GATE_RESULT_FAILED;
238 gate_uri_t url = GATE_INIT_EMPTY;
239 gate_uint32_t http_status = 0;
240 gate_memstream_t* ptr_content = NULL;
241 gate_property_t jsonprops = GATE_INIT_EMPTY;
242 gate_json_result_t jsonresult = GATE_INIT_EMPTY;
243 gate_size_t data_size = 0;
244 char const* ptr_data = NULL;
245 char query_buffer[1024];
246 gate_strbuilder_t query_builder = GATE_INIT_EMPTY;
247 gate_bool_t png_image = false;
248
249 do
250 {
251 if (request->image_type == GATE_TECH_GEOMAPS_TYPE_ROADMAP)
252 {
253 ret = gate_uri_parse(&url, &bing_road_url);
254 png_image = true;
255 }
256 else if (request->image_type == GATE_TECH_GEOMAPS_TYPE_SATELLITEMAP)
257 {
258 ret = gate_uri_parse(&url, &bing_aerial_url);
259 }
260 else if (request->image_type == (GATE_TECH_GEOMAPS_TYPE_ROADMAP | GATE_TECH_GEOMAPS_TYPE_SATELLITEMAP))
261 {
262 ret = gate_uri_parse(&url, &bing_aerialwithlabels_url);
263 }
264 else
265 {
266 ret = GATE_RESULT_INVALIDARG;
267 }
268 GATE_BREAK_IF_FAILED(ret);
269
270 gate_strbuilder_create_static(&query_builder, query_buffer, sizeof(query_buffer), 0);
271 create_bing_query(&query_builder,
272 minlat, minlong, maxlat, maxlong,
273 request->image_width, request->image_height, true, png_image, &bing_apikey);
274 gate_strbuilder_to_string(&query_builder, &url.query);
275
276 ptr_content = gate_memstream_create(256);
277 if (NULL == ptr_content)
278 {
279 ret = GATE_RESULT_OUTOFMEMORY;
280 break;
281 }
282
283 ret = gate_tech_webapi_get(context, &url, NULL, &http_status, (gate_stream_t*)ptr_content, NULL);
284 GATE_BREAK_IF_FAILED(ret);
285
286 ret = gate_json_parse((gate_stream_t*)ptr_content, &jsonprops, &jsonresult);
287 GATE_BREAK_IF_FAILED(ret);
288 if (!jsonresult.succeeded)
289 {
290 ret = GATE_RESULT_INVALIDDATA;
291 break;
292 }
293 ret = extract_properties(&jsonprops, response);
294 GATE_BREAK_IF_FAILED(ret);
295
296 // we have required meta data, now retrieve image content
297
298 gate_strbuilder_release(&query_builder);
299 gate_strbuilder_create_static(&query_builder, query_buffer, sizeof(query_buffer), 0);
300 create_bing_query(&query_builder,
301 response->min_latitude, response->min_longitude, response->max_latitude, response->max_longitude,
302 response->image_width, response->image_height, false, png_image, &bing_apikey);
303 // release old query, emplace new one
304 gate_string_release(&url.query);
305 gate_strbuilder_to_string(&query_builder, &url.query);
306
307 gate_memstream_discard(ptr_content, gate_memstream_size(ptr_content));
308
309 ret = gate_tech_webapi_get(context, &url, NULL, &http_status, (gate_stream_t*)ptr_content, NULL);
310 GATE_BREAK_IF_FAILED(ret);
311
312 data_size = gate_memstream_size(ptr_content);
313 ptr_data = gate_memstream_get_data(ptr_content);
314 gate_blob_create(&response->image_data, ptr_data, data_size);
315 response->image_format = png_image ? GATE_TECH_GEOMAPS_IMAGE_PNG : GATE_TECH_GEOMAPS_IMAGE_JPEG;
316
317 } while (0);
318
319 gate_property_destroy(&jsonprops);
320 if (ptr_content != NULL)
321 {
322 gate_object_release(ptr_content);
323 }
324 gate_uri_destroy(&url);
325 gate_strbuilder_release(&query_builder);
326 return ret;
327 }
328 */
329
330 1 static void azuremaps_read_api_key(gate_string_t* out_key)
331 {
332 static gate_string_t const subscription_key_value = GATE_STRING_INIT_STATIC("7LvLezLgOna4sU5bmBpqD5jAXdglfL8bcl3RaCjDBoVQAvfAgpvUJQQJ99BHAC5RqLJ2Rc9zAAAgAZMPDiUP");
333 1 *out_key = subscription_key_value;
334 1 }
335
336 static gate_real32_t const azure_R = 6378137.0f;
337 static gate_real32_t const azure_world_meters = 6378137.0f * GATE_MATH_CONST_PI * 2.0f;
338 static gate_real32_t const azure_tile_size = 256.0f;
339 static gate_real32_t const pi_4 = GATE_MATH_CONST_PI / 4.0f;
340 static gate_real32_t const pi_2 = GATE_MATH_CONST_PI / 2.0f;
341 static gate_real32_t const meters_per_pixel_zoom_0 = 156543.03392804097f;
342
343 1 static gate_real32_t get_mercator_meters_from_geopos_x(gate_real32_t longitude)
344 {
345 1 gate_real32_t const l = gate_math_deg2rad(longitude);
346 1 return azure_R * l;
347 }
348
349 1 static gate_real32_t get_mercator_meters_from_geopos_y(gate_real32_t latitude)
350 {
351 1 gate_real32_t const ph = gate_math_deg2rad(latitude);
352 1 return azure_R * gate_math_log(gate_math_tan(pi_4 + ph * 0.5f));
353 }
354
355 2 static gate_real32_t get_longitude_from_mercator_meters(gate_real32_t x)
356 {
357 2 return gate_math_rad2deg(x / azure_R);
358 }
359 2 static gate_real32_t get_latitude_from_mercator_meters(gate_real32_t y)
360 {
361 2 return gate_math_rad2deg(2.0 * gate_math_atan(gate_math_exp(y / azure_R)) - pi_2);
362 }
363
364 1 static gate_real32_t get_meters_per_pixel(gate_real32_t latitude, gate_uint16_t zoom_level)
365 {
366 1 const gate_real32_t zoom_factor = 1.0f / (gate_real32_t)(gate_math_pow_i64(2, zoom_level));
367 1 return meters_per_pixel_zoom_0 * gate_math_cos(gate_math_deg2rad(latitude)) * zoom_factor;
368 }
369
370 2 static gate_uint16_t azuremaps_calc_zoom_factor(gate_real32_t radius_meters, gate_uint16_t pixel_width)
371 {
372 2 gate_real32_t const view_meters = radius_meters * 2.0;
373 2 gate_real32_t const value = (azure_world_meters * (gate_real32_t)pixel_width) / (azure_tile_size * view_meters);
374 2 gate_real64_t const zoom = gate_math_floor(gate_math_log2(value));
375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (zoom <= 1.0) return 1;
376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (zoom >= 20.0) return 20;
377 2 return (gate_uint16_t)zoom;
378 }
379
380 1 static gate_result_t azuremaps_fetch_static_image(
381 gate_tech_webapi_context_t* context,
382 gate_string_t const* api_key,
383 gate_real32_t longitude, gate_real32_t latitude,
384 gate_real32_t radius_meters, gate_enumint_t image_type,
385 gate_uint16_t image_width, gate_uint16_t image_height,
386 gate_blob_t* png_data)
387 {
388 1 gate_result_t ret = GATE_RESULT_FAILED;
389 1 gate_string_t subscription_key_value = GATE_INIT_EMPTY;
390 1 gate_strbuilder_t builder = GATE_INIT_EMPTY;
391 char url_buffer[1024];
392 1 gate_string_t url = GATE_INIT_EMPTY;
393 1 gate_uri_t uri = GATE_INIT_EMPTY;
394 1 gate_map_t http_headers = GATE_INIT_EMPTY;
395 1 gate_memstream_t* response_stream = NULL;
396
397 do
398 {
399 1 gate_uint16_t zoom_factor = azuremaps_calc_zoom_factor(radius_meters, image_width);
400 1 gate_uint32_t status_code = 0;
401 1 char const* image_type_str = NULL;
402 static gate_string_t const subscription_key_header = GATE_STRING_INIT_STATIC("subscription-key");
403
404
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_string_is_empty(api_key))
405 {
406 1 azuremaps_read_api_key(&subscription_key_value);
407 }
408 else
409 {
410 gate_string_duplicate(&subscription_key_value, api_key);
411 }
412
413
414 1 gate_strbuilder_create_static(&builder, url_buffer, sizeof(url_buffer), 0);
415
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 switch(image_type)
416 {
417 1 case GATE_TECH_GEOMAPS_TYPE_SATELLITEMAP:
418 1 image_type_str = "microsoft.imagery";
419 1 break;
420 case GATE_TECH_GEOMAPS_TYPE_ROADMAP:
421 default:
422 image_type_str = "microsoft.base.road";
423 break;
424 }
425
426 1 gate_strbuilder_append(&builder,
427 GATE_PRINT_CSTR, "https://atlas.microsoft.com/map/static?api-version=2024-04-01",
428 GATE_PRINT_CSTR, "&center=", GATE_PRINT_R64, longitude, GATE_PRINT_CSTR, ",", GATE_PRINT_R64, latitude,
429 GATE_PRINT_CSTR, "&zoom=", GATE_PRINT_UI16, zoom_factor,
430 GATE_PRINT_CSTR, "&width=", GATE_PRINT_UI16, image_width,
431 GATE_PRINT_CSTR, "&height=", GATE_PRINT_UI16, image_height,
432 GATE_PRINT_CSTR, "&tilesetId=", GATE_PRINT_CSTR, image_type_str,
433 GATE_PRINT_END);
434
435
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_strbuilder_to_string(&builder, &url))
436 {
437 ret = GATE_RESULT_OUTOFMEMORY;
438 break;
439 }
440
441 1 ret = gate_uri_parse(&uri, &url);
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
443
444 1 response_stream = gate_memstream_create(0);
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (response_stream == NULL)
446 {
447 ret = GATE_RESULT_OUTOFMEMORY;
448 break;
449 }
450
451
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_util_stringmap_create(&http_headers))
452 {
453 ret = GATE_RESULT_OUTOFMEMORY;
454 break;
455 }
456 1 gate_util_stringmap_add_string(&http_headers, &subscription_key_header, &subscription_key_value);
457
458 1 ret = gate_tech_webapi_get(context, &uri, &http_headers, &status_code, (gate_stream_t*)response_stream, NULL);
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (status_code != 200)
461 {
462 ret = GATE_RESULT_EXECUTIONFAILED;
463 break;
464 }
465
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if (NULL == gate_blob_create(png_data, gate_memstream_get_data(response_stream), gate_memstream_size(response_stream)))
466 {
467 ret = GATE_RESULT_OUTOFMEMORY;
468 break;
469 }
470
471 /* success state */
472 1 ret = GATE_RESULT_OK;
473 } while (0);
474
475
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (response_stream)
476 {
477 1 gate_object_release(response_stream);
478 }
479 1 gate_map_destroy(&http_headers);
480 1 gate_uri_destroy(&uri);
481 1 gate_string_release(&url);
482 1 gate_strbuilder_release(&builder);
483 1 gate_string_release(&subscription_key_value);
484 1 return ret;
485 }
486
487 1 static gate_result_t azuremaps_load_map_info(gate_tech_webapi_context_t* context,
488 gate_tech_webapi_geomaps_request_t* request,
489 gate_tech_webapi_geomaps_response_t* response)
490 {
491 gate_result_t ret;
492 do
493 {
494
495 3 ret = azuremaps_fetch_static_image(context, NULL,
496 request->center_longitude, request->center_latitude, request->radius_meters,
497 1 request->image_type, request->image_width, request->image_height, &response->image_data);
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
499
500 1 response->image_width = request->image_width;
501 1 response->image_height = request->image_height;
502 1 response->center_latitude = request->center_latitude;
503 1 response->center_longitude = request->center_longitude;
504
505 {
506 1 const gate_uint16_t zoom_factor = azuremaps_calc_zoom_factor(request->radius_meters, request->image_width);
507 1 const gate_real32_t meters_per_pixel = get_meters_per_pixel(request->center_latitude, zoom_factor);
508 1 const gate_real32_t half_width = meters_per_pixel * request->image_width * 0.5f;
509 1 const gate_real32_t half_height = meters_per_pixel * request->image_height * 0.5f;
510 1 const gate_real32_t x = get_mercator_meters_from_geopos_x(request->center_longitude);
511 1 const gate_real32_t y = get_mercator_meters_from_geopos_y(request->center_latitude);
512
513 1 response->min_longitude = get_longitude_from_mercator_meters(x - half_width);
514 1 response->min_latitude = get_latitude_from_mercator_meters(y - half_height);
515 1 response->max_longitude = get_longitude_from_mercator_meters(x + half_width);
516 1 response->max_latitude = get_latitude_from_mercator_meters(y + half_height);
517
518 1 response->width_meters = meters_per_pixel * request->image_width;
519 1 response->height_meters = meters_per_pixel * request->image_height;
520 }
521
522 1 response->image_type = request->image_type;
523 1 response->image_format = GATE_TECH_GEOMAPS_IMAGE_PNG;
524 } while (0);
525 1 return ret;
526 }
527
528 1 gate_result_t gate_tech_webapi_geomaps(gate_tech_webapi_context_t* context,
529 gate_tech_webapi_geomaps_request_t* request,
530 gate_tech_webapi_geomaps_response_t* response)
531 {
532 1 return azuremaps_load_map_info(context, request, response);
533 }
534