2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <maps_coordinates.h>
21 #include "mapzen_jsonparser.hpp"
22 #include "rapidjson/document.h"
25 #include "mapzen_queue.h"
26 #include "mapzen_debug.h"
27 #include "mapzen_types.h"
28 #include "mapzen_util.h"
38 #define ROUTE_UNIT_CONVERSION_MILE_TO_M(x) (1609.34 * (x))
39 #define ROUTE_UNIT_CONVERSION_MILE_TO_KM(x) (1.60934 * (x))
40 #define ROUTE_UNIT_CONVERSION_MILE_TO_FT(x) (5280 * (x))
41 #define ROUTE_UNIT_CONVERSION_MILE_TO_YD(x) (1760 * (x))
43 static route_unit __route_unit = UNIT_KM;
44 static route_type __route_type = COSTING_AUTO;
45 constexpr double kPolylinePrecision = 1E6;
46 constexpr double kInvPolylinePrecision = 1.0 / kPolylinePrecision;
49 //TODO: port this to c? or port the whole project to c++ or add all the proper externs
50 void decode_shape(const std::string& encoded, std::vector<coords_s>& output) {
51 // what byte are we looking at
54 // Handy lambda to turn a few bytes of an encoded string into an integer
55 auto deserialize = [&encoded, &i](const int previous) {
56 // Grab each 5 bits and mask it in where it belongs using the shift
57 int byte, shift = 0, result = 0;
59 byte = static_cast<int>(encoded[i++]) - 63;
60 result |= (byte & 0x1f) << shift;
62 } while (byte >= 0x20);
64 // Undo the left shift from above or the bit flipping and add
65 // to previous since its an offset
66 return previous + (result & 1 ? ~(result >> 1) : (result >> 1));
69 // Iterate over all characters of the encoded shape string
70 int last_lon = 0, last_lat = 0;
71 while (i < encoded.length())
73 // Decode the coordinates, lat first
74 int lat = deserialize(last_lat);
75 int lon = deserialize(last_lon);
77 // Shift the decimal point 5 places to the left and add to the output
79 ll.latitude = static_cast<double>(lat) * kInvPolylinePrecision;
80 ll.longitude = static_cast<double>(lon) * kInvPolylinePrecision;
81 output.emplace_back(std::move(ll));
83 // Remember the last one we encountered
90 static mapzen_error_e __convert_status(int status)
92 mapzen_error_e error = MAPZEN_ERROR_UNKNOWN;
96 /* Successful Geocode call */
97 error = MAPZEN_ERROR_NONE;
102 /* Error with input - Illegal argument from request */
103 error = MAPZEN_ERROR_INVALID_PARAMETER;
108 /* Key related error - Invalid key */
109 error = MAPZEN_ERROR_KEY_NOT_AVAILABLE;
115 error = MAPZEN_ERROR_UNKNOWN;
121 error = MAPZEN_ERROR_NETWORK_UNREACHABLE;
129 bool __get_string(const rapidjson::Value& obj, const char* key, char** value)
131 //if we have the key and its not an empty value
132 rapidjson::Value::ConstMemberIterator itr = obj.FindMember(key);
133 if(itr != obj.MemberEnd() && itr->value.GetStringLength()){
134 (*value) = (gchar *)g_malloc(itr->value.GetStringLength() + sizeof(rapidjson::Document::Ch));
135 strncpy((*value), itr->value.GetString(), itr->value.GetStringLength());
136 memset((*value) + itr->value.GetStringLength(), 0, sizeof(rapidjson::Document::Ch));
142 return *value != NULL;
145 /************ GEOCODE ***************/
148 static void __parse_geocode_response(char *response, int size, int *status, GList **coordsList)
150 MAP_DEBUG("Inside __parse_geocode_response..");
153 if (!response || !status || !coordsList) return;
155 //so far we have nothing
159 //crack open that json
160 rapidjson::Document document;
161 document.Parse(std::string(response, size).c_str());
162 rapidjson::Value::ConstMemberIterator features = document.FindMember("features");
163 if(features != document.MemberEnd() && features->value.IsArray()) {
165 for (rapidjson::Value::ConstValueIterator f = features->value.Begin(); f != features->value.End(); ++f) {
166 //it has to have geometry
167 rapidjson::Value::ConstMemberIterator geom = f->FindMember("geometry");
168 if(geom != f->MemberEnd()) {
170 rapidjson::Value::ConstMemberIterator type = geom->value.FindMember("type");
171 if(type == geom->value.MemberEnd() || strcmp(type->value.GetString(), "Point"))
174 rapidjson::Value::ConstMemberIterator coords = geom->value.FindMember("coordinates");
175 if(coords == geom->value.MemberEnd() || !coords->value.IsArray() || coords->value.Size() != 2)
178 coords_s *coord = (coords_s *)g_malloc0(sizeof(coords_s));
180 coord->longitude = coords->value[0].GetDouble();
181 coord->latitude = coords->value[1].GetDouble();
184 if (*coordsList == NULL)
185 *coordsList = g_list_append(*coordsList, coord);
187 *coordsList = g_list_insert_before(*coordsList, NULL, coord);
194 /****************** REVERSE GEOCODE *********************/
196 static void __parse_revgeocode_response(char *response, int size, int *status, mapzen_address_resp_s **respAddr)
198 if (!response || !status || !respAddr) return;
200 //so far we have nothing
204 //crack open that json
205 rapidjson::Document document;
206 document.Parse(std::string(response, size).c_str());
207 rapidjson::Value::ConstMemberIterator features = document.FindMember("features");
208 if(features != document.MemberEnd() && features->value.IsArray()) {
210 for (rapidjson::Value::ConstValueIterator f = features->value.Begin(); f != features->value.End(); ++f) {
211 //it has to have geometry
212 rapidjson::Value::ConstMemberIterator geom = f->FindMember("geometry");
213 if(geom != f->MemberEnd()) {
215 rapidjson::Value::ConstMemberIterator type = geom->value.FindMember("type");
216 if(type == geom->value.MemberEnd() || strcmp(type->value.GetString(), "Point"))
219 rapidjson::Value::ConstMemberIterator coords = geom->value.FindMember("coordinates");
220 if(coords == geom->value.MemberEnd() || !coords->value.IsArray() || coords->value.Size() != 2)
223 //NOTE: it seems as though the tizen maps plugin api assumes that reverse geocode results will
224 //actually be at the coordinates where you requested the reverse geocode. the mapzen api can return
225 //POIS which are some distance away from the location and currently this is not accounted for :o(
227 //get out the address information
228 rapidjson::Value::ConstMemberIterator properties = f->FindMember("properties");
229 if(properties != f->MemberEnd()) {
230 //fill this out as we go
231 *respAddr = (mapzen_address_resp_s *)g_malloc(sizeof(mapzen_address_resp_s));
232 bool something = false;
233 something = __get_string(properties->value, "street", &(*respAddr)->street) || something;
234 something = __get_string(properties->value, "neighbourhood", &(*respAddr)->neighbourhood) || something;
235 something = __get_string(properties->value, "housenumber", &(*respAddr)->housenumber) || something;
236 something = __get_string(properties->value, "localadmin", &(*respAddr)->localadmin) || something;
237 something = __get_string(properties->value, "county", &(*respAddr)->county) || something;
238 something = __get_string(properties->value, "region", &(*respAddr)->region) || something;
239 something = __get_string(properties->value, "country", &(*respAddr)->country) || something;
240 something = __get_string(properties->value, "country_a", &(*respAddr)->country_a) || something;
241 something = __get_string(properties->value, "postalcode", &(*respAddr)->postalcode) || something;
242 //if everything was null thats pretty much unusable
243 //TODO: these are pretty weak criteria..
247 //forget the rest, we have one with something in it
258 /**************** PLACE SEARCH ********************/
260 static void __parse_place_response(char *response, int size, GList **placeList)
262 MAP_DEBUG("Inside __parse_place_response.");
264 if (!response || !placeList) return;
268 //crack open that json
269 rapidjson::Document document;
270 document.Parse(std::string(response, size).c_str());
271 rapidjson::Value::ConstMemberIterator features = document.FindMember("features");
272 if(features != document.MemberEnd() && features->value.IsArray()) {
274 for (rapidjson::Value::ConstValueIterator f = features->value.Begin(); f != features->value.End(); ++f) {
275 //it has to have geometry
276 rapidjson::Value::ConstMemberIterator geom = f->FindMember("geometry");
277 if(geom != f->MemberEnd()) {
279 rapidjson::Value::ConstMemberIterator type = geom->value.FindMember("type");
280 if(type == geom->value.MemberEnd() || strcmp(type->value.GetString(), "Point"))
283 rapidjson::Value::ConstMemberIterator coords = geom->value.FindMember("coordinates");
284 if(coords == geom->value.MemberEnd() || !coords->value.IsArray() || coords->value.Size() != 2)
288 coordinate.longitude = coords->value[0].GetDouble();
289 coordinate.latitude = coords->value[1].GetDouble();
291 //get out the address information
292 rapidjson::Value::ConstMemberIterator properties = f->FindMember("properties");
293 if(properties != f->MemberEnd()) {
294 //fill this out as we go
295 mapzen_place_resp_s *respPlaces = (mapzen_place_resp_s *)g_malloc0(sizeof(mapzen_place_resp_s));
299 respPlaces->place_id = NULL;
300 respPlaces->categories = NULL;
301 respPlaces->display_name = NULL;
302 respPlaces->address = NULL;
304 bool something = false;
305 something = __get_string(properties->value, "gid", &respPlaces->place_id) || something;
306 something = __get_string(properties->value, "name", &respPlaces->display_name) || something;
308 respPlaces->address = (mapzen_address_resp_s *)g_malloc(sizeof(mapzen_address_resp_s));
310 something = __get_string(properties->value, "housenumber", &respPlaces->address->housenumber) || something;
311 something = __get_string(properties->value, "street", &respPlaces->address->street) || something;
312 something = __get_string(properties->value, "neighbourhood", &respPlaces->address->neighbourhood) || something;
313 something = __get_string(properties->value, "county", &respPlaces->address->county) || something;
314 something = __get_string(properties->value, "region", &respPlaces->address->region) || something;
315 something = __get_string(properties->value, "country", &respPlaces->address->country) || something;
316 something = __get_string(properties->value, "country_a", &respPlaces->address->country_a) || something;
317 something = __get_string(properties->value, "locality", &respPlaces->address->localadmin) || something;
318 something = __get_string(properties->value, "postalcode", &respPlaces->address->postalcode) || something;
320 respPlaces->coordinates = coordinate;
322 respPlaces->categories = NULL;
323 rapidjson::Value::ConstMemberIterator categories = properties->value.FindMember("category");
324 if (categories != geom->value.MemberEnd() && categories->value.IsArray()) {
325 for (rapidjson::SizeType i = 0; i < categories->value.Size(); i++) {
326 if (respPlaces->categories == NULL)
327 respPlaces->categories = g_list_append(respPlaces->categories, g_strdup(categories->value[i].GetString()));
329 respPlaces->categories = g_list_insert_before(respPlaces->categories, NULL, g_strdup(categories->value[i].GetString()));
337 if (*placeList == NULL)
338 *placeList = g_list_append(*placeList, respPlaces);
340 *placeList = g_list_insert_before(*placeList, NULL, respPlaces);
348 /********************* ROUTE RESPONSE ***********************/
350 static void __process_shape(std::vector<coords_s>& decoded_shape, GList **shapePoints)
352 MAP_DEBUG(">>>>> START __process_shape");
354 for (auto& shape_pt : decoded_shape) {
355 coords_s *coords = (coords_s *)g_malloc0(sizeof(coords_s));
357 coords->latitude = shape_pt.latitude;
358 coords->longitude = shape_pt.longitude;
359 if ((*shapePoints) == NULL)
360 (*shapePoints) = g_list_append((*shapePoints), (gpointer)coords);
362 (*shapePoints) = g_list_insert_before((*shapePoints), NULL, (gpointer)coords);
363 // MAP_DEBUG(">>>>> PROCESS __process_shape: lat,lon=%f,%f", coords->latitude, coords->longitude);
366 MAP_DEBUG(">>>>> END __process_shape");
369 static void __set_bounding_box(rapidjson::Value::ConstMemberIterator& summary, rectangle_s& bounding_box)
371 rapidjson::Value::ConstMemberIterator min_lat = summary->value.FindMember("min_lat");
372 rapidjson::Value::ConstMemberIterator min_lon = summary->value.FindMember("min_lon");
373 rapidjson::Value::ConstMemberIterator max_lat = summary->value.FindMember("max_lat");
374 rapidjson::Value::ConstMemberIterator max_lon = summary->value.FindMember("max_lon");
375 if ((min_lat != summary->value.MemberEnd())
376 && (min_lon != summary->value.MemberEnd())
377 && (max_lat != summary->value.MemberEnd())
378 && (max_lon != summary->value.MemberEnd())) {
379 bounding_box.top_left.latitude = max_lat->value.GetDouble();
380 bounding_box.top_left.longitude = min_lon->value.GetDouble();
381 bounding_box.bottom_right.latitude = min_lat->value.GetDouble();
382 bounding_box.bottom_right.longitude = max_lon->value.GetDouble();
386 static void __parse_maneuvers(rapidjson::Value::ConstMemberIterator maneuvers, mapzen_route_segment *segment_resp, std::vector<coords_s>& segment_shape)
388 MAP_DEBUG(">>>>> START __parse_maneuvers");
390 rapidjson::Value::ConstMemberIterator begin_shape_index, end_shape_index, maneuver_time,
391 maneuver_distance, type, travel_type, travel_mode, street_names_resp;
392 rapidjson::Value::ConstValueIterator street_name;
394 for (rapidjson::Value::ConstValueIterator maneuver =
395 maneuvers->value.Begin(); maneuver != maneuvers->value.End();
397 mapzen_route_maneuver *maneuver_resp = (mapzen_route_maneuver *)g_malloc(sizeof(mapzen_route_maneuver));
400 // Set maneuver start point
401 begin_shape_index = maneuver->FindMember("begin_shape_index");
402 if (begin_shape_index != maneuver->MemberEnd()) {
403 maneuver_resp->start_point = segment_shape.at(begin_shape_index->value.GetInt());
404 MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: maneuver_resp->start_point=%f,%f", maneuver_resp->start_point.latitude, maneuver_resp->start_point.longitude);
407 // Set maneuver end point
408 end_shape_index = maneuver->FindMember("end_shape_index");
409 if (end_shape_index != maneuver->MemberEnd()) {
410 maneuver_resp->end_point = segment_shape.at(end_shape_index->value.GetInt());
411 MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: maneuver_resp->end_point=%f,%f", maneuver_resp->end_point.latitude, maneuver_resp->end_point.longitude);
414 // Set maneuver distance
415 maneuver_distance = maneuver->FindMember("length");
416 if (maneuver_distance != maneuver->MemberEnd()) {
417 MAP_DEBUG(">>>>> __parse_maneuvers: PROCESS maneuver_distance: %f", maneuver_distance->value.GetDouble());
418 maneuver_resp->distance = maneuver_distance->value.GetDouble();
422 maneuver_time = maneuver->FindMember("time");
423 if (maneuver_time != maneuver->MemberEnd()) {
424 MAP_DEBUG(">>>>> __parse_maneuvers: PROCESS maneuver_time: %d", maneuver_time->value.GetInt());
425 maneuver_resp->time = maneuver_time->value.GetInt();
429 type = maneuver->FindMember("type");
430 if (type != maneuver->MemberEnd()) {
431 maneuver_resp->type = convert_int_to_mapzen_maneuver_type(type->value.GetInt());
432 MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: type=%d", maneuver_resp->type);
435 // Set maneuver instruction
436 __get_string((*maneuver), "instruction", &maneuver_resp->instruction);
438 // Set maneuver street names
439 maneuver_resp->street_name = NULL;
440 street_names_resp = maneuver->FindMember("street_names");
441 if (street_names_resp != maneuver->MemberEnd() && street_names_resp->value.IsArray()) {
442 std::string street_name;
444 for (rapidjson::Value::ConstValueIterator street_name_resp = street_names_resp->value.Begin();
445 street_name_resp != street_names_resp->value.End(); ++street_name_resp) {
446 street_name += std::string(street_name.size()? "/": "");
447 street_name += street_name_resp->GetString();
450 if (street_name.size() > 0) {
451 MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: street_name=%s", street_name.c_str());
452 maneuver_resp->street_name = (gchar *)g_malloc0(street_name.size() + 1);
453 if (maneuver_resp->street_name) {
454 strncpy (maneuver_resp->street_name, street_name.c_str(), sizeof(gchar) * street_name.size());
455 MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: maneuver_resp->street_name=%s", maneuver_resp->street_name);
460 // Append maneuver to maneuver list
461 if (segment_resp->maneuvers == NULL) {
462 MAP_DEBUG(">>>>> __parse_route_response: PROCESS segment_resp->maneuvers == NULL) - append");
463 segment_resp->maneuvers = g_list_append(segment_resp->maneuvers, (gpointer)maneuver_resp);
465 MAP_DEBUG(">>>>> __parse_route_response: PROCESS segment_resp->maneuvers != NULL) - insert before");
466 segment_resp->maneuvers = g_list_insert_before(segment_resp->maneuvers, NULL, (gpointer)maneuver_resp);
468 } // end process each maneuver
470 MAP_DEBUG(">>>>> END __parse_maneuvers");
473 static bool __determine_segment_origin_destination(const rapidjson::Value& locations,
474 rapidjson::SizeType& location_index, coords_s& origin,
475 coords_s& destination) {
476 bool origin_set = false;
477 bool destination_set = false;
480 for (rapidjson::SizeType i = location_index; i < locations.Size(); i++) {
481 auto& location = locations[i];
482 if (location["type"] == "break") {
483 origin.latitude = location["lat"].GetDouble();
484 origin.longitude = location["lon"].GetDouble();
486 // Increment location index to find segment destination
487 location_index = ++i;
493 for (rapidjson::SizeType i = location_index; i < locations.Size(); i++) {
494 auto& location = locations[i];
495 if (location["type"] == "break") {
496 destination.latitude = location["lat"].GetDouble();
497 destination.longitude = location["lon"].GetDouble();
498 destination_set = true;
499 // Assign location index for next segment origin
505 // Validate that both origin and destination are set
506 if (origin_set and destination_set) {
513 static void __parse_route_response(char *response, int size, int *status, mapzen_route_resp_s **routeResp) {
514 MAP_DEBUG(">>>>> START __parse_route_response");
516 if (!response || !status || !routeResp)
519 MAP_DEBUG(">>>>> PROCESS __parse_route_response: ROUTE RESPONSE returned=%s", response);
521 rapidjson::Document document;
522 document.Parse(std::string(response, size).c_str());
523 rapidjson::Value::MemberIterator trip = document.FindMember("trip");
524 if (trip == document.MemberEnd()) {
525 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip object not found in response");
530 rapidjson::Value::ConstMemberIterator trip_status = trip->value.FindMember("status");
531 if (trip_status != trip->value.MemberEnd()) {
532 *status = trip_status->value.GetInt();
533 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip_status=%d", *status);
536 MAP_DEBUG(">>>>> PROCESS __parse_route_response: invalid status in response");
540 // Create route response object and initialize lists to NULL
541 *routeResp = (mapzen_route_resp_s *) g_malloc(sizeof(mapzen_route_resp_s));
544 (*routeResp)->segments = NULL;
545 (*routeResp)->shapePoints = NULL;
547 // Get trip locations
548 rapidjson::SizeType location_index = 0;
549 rapidjson::Value& locations = trip->value["locations"];
550 MAP_DEBUG(">>>>> PROCESS __parse_route_response: locations.Size(): %d", locations.Size());
553 rapidjson::Value& mapzen_origin = locations[0];
554 (*routeResp)->origin.latitude = mapzen_origin["lat"].GetDouble();
555 (*routeResp)->origin.longitude = mapzen_origin["lon"].GetDouble();
556 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip origin: %f,%f", (*routeResp)->origin.latitude, (*routeResp)->origin.longitude);
558 // Set trip destination
559 rapidjson::Value& mapzen_destination = locations[locations.Size()-1];
560 (*routeResp)->destination.latitude = mapzen_destination["lat"].GetDouble();
561 (*routeResp)->destination.longitude = mapzen_destination["lon"].GetDouble();
562 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip destination: %f,%f", (*routeResp)->destination.latitude, (*routeResp)->destination.longitude);
565 __get_string(trip->value, "language", &(*routeResp)->language);
567 // Set distance units
568 // TODO maybe just read units from response and set value
569 (*routeResp)->distance_unit = __route_unit;
570 MAP_DEBUG(">>>>> PROCESS __parse_route_response: distance_unit=%d", (*routeResp)->distance_unit);
572 // Process trip summary
573 rapidjson::Value::ConstMemberIterator trip_summary = trip->value.FindMember("summary");
574 if (trip_summary != trip->value.MemberEnd()) {
576 rapidjson::Value::ConstMemberIterator trip_distance = trip_summary->value.FindMember("length");
577 if (trip_distance != trip_summary->value.MemberEnd()) {
578 (*routeResp)->distance = trip_distance->value.GetDouble();
579 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip length : %f", (*routeResp)->distance);
583 rapidjson::Value::ConstMemberIterator trip_time = trip_summary->value.FindMember("time");
584 if (trip_time != trip_summary->value.MemberEnd()) {
585 (*routeResp)->time = trip_time->value.GetInt();
586 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip time: %d", trip_time->value.GetInt());
589 // Set trip bounding box
590 __set_bounding_box(trip_summary, (*routeResp)->bounding_box);
591 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip_bounding_box.top_left =%f,%f", (*routeResp)->bounding_box.top_left.latitude, (*routeResp)->bounding_box.top_left.longitude);
592 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip_bounding_box.bottom_right =%f,%f", (*routeResp)->bounding_box.bottom_right.latitude, (*routeResp)->bounding_box.bottom_right.longitude);
596 (*routeResp)->type = __route_type;
597 MAP_DEBUG(">>>>> PROCESS __parse_route_response: route_type=%d", (*routeResp)->type);
599 ///////////////////////////////////////////////////////////////////////////
600 // Process segments (legs)
601 rapidjson::Value::MemberIterator legs = trip->value.FindMember("legs");
602 if (legs == trip->value.MemberEnd() || !legs->value.IsArray()) {
603 MAP_DEBUG(">>>>> PROCESS __parse_route_response: invalid legs in response");
606 for (rapidjson::Value::ConstValueIterator leg = legs->value.Begin(); leg != legs->value.End(); ++leg) {
607 // Determine segment origin and destination
608 coords_s segment_origin;
609 coords_s segment_destination;
610 if (!__determine_segment_origin_destination(locations, location_index, segment_origin, segment_destination)) {
611 MAP_DEBUG(">>>>> PROCESS __parse_route_response: invalid segment origin and destination");
615 // Create segment response
616 mapzen_route_segment *segment_resp = (mapzen_route_segment *)g_malloc(sizeof(mapzen_route_segment));
617 segment_resp->maneuvers = NULL;
618 segment_resp->shapePoints = NULL;
620 // Set segment origin
621 segment_resp->origin = segment_origin;
622 MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_origin: %f,%f", segment_origin.latitude, segment_origin.longitude);
624 // Set segment destination
625 segment_resp->destination = segment_destination;
626 MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_destination: %f,%f", segment_destination.latitude, segment_destination.longitude);
628 // Process segment summary
629 rapidjson::Value::ConstMemberIterator leg_summary = leg->FindMember("summary");
630 if (leg_summary != leg->MemberEnd()) {
631 // Set segment distance
632 rapidjson::Value::ConstMemberIterator leg_distance = leg_summary->value.FindMember("length");
633 if (leg_distance != leg_summary->value.MemberEnd()) {
634 segment_resp->distance = leg_distance->value.GetDouble();
635 MAP_DEBUG(">>>>> PROCESS __parse_route_response: leg length=%f", segment_resp->distance);
639 rapidjson::Value::ConstMemberIterator leg_time = leg_summary->value.FindMember("time");
640 if (leg_time != leg_summary->value.MemberEnd()) {
641 segment_resp->time = leg_time->value.GetInt();
642 MAP_DEBUG(">>>>> PROCESS __parse_route_response: leg time=%d", segment_resp->time);
645 // Set segment bounding box
646 __set_bounding_box(leg_summary, segment_resp->bounding_box);
647 MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_bounding_box.top_left =%f,%f", segment_resp->bounding_box.top_left.latitude, segment_resp->bounding_box.top_left.longitude);
648 MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_bounding_box.bottom_right =%f,%f", segment_resp->bounding_box.bottom_right.latitude, segment_resp->bounding_box.bottom_right.longitude);
651 // Get segment encoded shape and decode
652 auto encoded_shape = leg->FindMember("shape");
653 MAP_DEBUG(">>>>> PROCESS __parse_route_response: ENCODED SHAPE=%s", encoded_shape->value.GetString());
654 std::vector<coords_s> decoded_shape;
655 decode_shape(encoded_shape->value.GetString(), decoded_shape);
656 MAP_DEBUG(">>>>> PROCESS __parse_route_response: Segment shape point count=%d", decoded_shape.size());
658 // Append shape for route trip and segment
659 // TODO - optimize/improve
660 // TODO - duplicated points between route trip and segments
661 // TODO - currently no generalization - test application has 500 point limit
662 MAP_DEBUG(">>>>> PROCESS __parse_route_response: PRE __process_shape");
663 __process_shape(decoded_shape, &((*routeResp)->shapePoints));
664 __process_shape(decoded_shape, &(segment_resp->shapePoints));
665 MAP_DEBUG(">>>>> PROCESS __parse_route_response: POST __process_shape");
667 rapidjson::Value::ConstMemberIterator maneuvers = leg->FindMember("maneuvers");
668 if (maneuvers == leg->MemberEnd() || !maneuvers->value.IsArray()) {
669 g_free(segment_resp);
673 ///////////////////////////////////////////////////////////////////////
674 // Process each maneuver
675 MAP_DEBUG(">>>>> PROCESS __parse_route_response: PRE __parse_maneuvers");
676 __parse_maneuvers(maneuvers, segment_resp, decoded_shape);
677 MAP_DEBUG(">>>>> PROCESS __parse_route_response: POST __parse_maneuvers");
678 ///////////////////////////////////////////////////////////////////////
680 // Add segment to segment list
681 if ((*routeResp)->segments == NULL) {
682 MAP_DEBUG(">>>>> PROCESS __parse_route_response: (*routeResp)->maneuvers == NULL) - append");
683 (*routeResp)->segments = g_list_append((*routeResp)->segments, (gpointer)segment_resp);
685 MAP_DEBUG(">>>>> PROCESS __parse_route_response: (*routeResp)->maneuvers != NULL) - insert before");
686 (*routeResp)->segments = g_list_insert_before((*routeResp)->segments, NULL, (gpointer)segment_resp);
688 } // end process each leg
689 ///////////////////////////////////////////////////////////////////////////
691 MAP_DEBUG(">>>>> END __parse_route_response");
694 void post_curl_response(char *response, int size, mapzen_resp_type type, void *user_data)
696 MAP_DEBUG(">>>>> START post_curl_response");
697 if (!response) return;
700 MAP_DEBUG("Response data is NULL");
704 MAP_DEBUG("Response received from Curl. [Size=%d]", size);
706 case RESP_TYPE_GEOCODE:
708 MAP_DEBUG("Inside Geocode JSON Parsing..");
710 MapzenGeocodeQueryData *queryData = (MapzenGeocodeQueryData *)user_data;
711 MapzenGeocodeResponseData *responseData = (MapzenGeocodeResponseData *)g_malloc(sizeof(MapzenGeocodeResponseData));
714 responseData->requestId = queryData->requestId;
715 responseData->geocode_cb = queryData->geocode_cb;
716 responseData->user_data = queryData->user_data;
718 if (response && (size > 0)) {
719 GList *coordsList = NULL;
720 __parse_geocode_response(response, size, &status, &coordsList);
722 if (coordsList != NULL) {
723 /* Put the response in queue */
724 responseData->error = __convert_status(status);
725 responseData->coords = coordsList;
727 /* Response parsing failure */
728 responseData->error = __convert_status(status);
729 responseData->coords = NULL;
732 responseData->error = __convert_status(status);
733 responseData->coords = NULL;
736 mapzen_push_to_queue(type, (gpointer)responseData);
745 case RESP_TYPE_REVGEOCODE:
747 MAP_DEBUG("Inside Rev Geocode JSON Parsing..");
749 MapzenRevGeocodeQueryData *queryData = (MapzenRevGeocodeQueryData *)user_data;
750 MapzenRevGeocodeResponseData *responseData = (MapzenRevGeocodeResponseData *)g_malloc(sizeof(MapzenRevGeocodeResponseData));
753 responseData->requestId = queryData->requestId;
754 responseData->reverse_geocode_cb = queryData->reverse_geocode_cb;
755 responseData->user_data = queryData->user_data;
757 if (response && (size > 0)) {
758 /* Coords Result GList */
759 mapzen_address_resp_s *addrResponse = NULL;
761 MAP_DEBUG("Rev Geocode :- Parsing json Response");
762 __parse_revgeocode_response(response, size, &status, &addrResponse);
764 if (addrResponse != NULL) {
765 /* Put the response in queue */
766 responseData->error = __convert_status(status);
767 responseData->addressDetails = addrResponse;
769 /* REPSONSE PARSING FAILURE */
770 MAP_DEBUG("addr Response is NULL");
771 responseData->error = __convert_status(status);
772 responseData->addressDetails = NULL;
775 MAP_DEBUG("JSON Response is NULL..");
776 responseData->error = __convert_status(status);
777 responseData->addressDetails = NULL;
779 mapzen_push_to_queue(type, (gpointer)responseData);
788 case RESP_TYPE_PLACES:
790 MAP_DEBUG("Inside Places JSON Parsing..");
791 MapzenPlaceQueryData *queryData = (MapzenPlaceQueryData *)user_data;
792 MapzenPlaceResponseData *responseData = (MapzenPlaceResponseData *)g_malloc(sizeof(MapzenPlaceResponseData));
795 responseData->requestId = queryData->requestId;
796 responseData->place_search_cb = queryData->place_search_cb;
797 responseData->user_data = queryData->user_data;
799 if (response && (size > 0)) {
800 /* Coords Result GList */
801 GList *placeList = NULL;
803 MAP_DEBUG("Search Places :- Parsing Json Response");
804 __parse_place_response(response, size, &placeList);
806 if (placeList != NULL) {
807 /* Put the response in queue */
808 responseData->error = MAPZEN_ERROR_NONE;
809 responseData->places = placeList;
811 /* REPSONSE PARSING FAILURE */
812 MAP_DEBUG("addr Response is NULL");
813 responseData->error = MAPZEN_ERROR_UNKNOWN;
814 responseData->places = NULL;
817 responseData->error = MAPZEN_ERROR_UNKNOWN;
818 responseData->places = NULL;
821 mapzen_push_to_queue(type, (gpointer)responseData);
831 case RESP_TYPE_PLACES_DETAILS:
833 MAP_DEBUG("Inside Places Details JSON Parsing..");
834 MapzenPlaceDetailsQueryData *queryData = (MapzenPlaceDetailsQueryData *)user_data;
835 MapzenPlaceDetailsResponseData *responseData = (MapzenPlaceDetailsResponseData *)g_malloc(sizeof(MapzenPlaceDetailsResponseData));
838 responseData->requestId = queryData->requestId;
839 responseData->get_place_details_cb = queryData->get_place_details_cb;
840 responseData->user_data = queryData->user_data;
842 if (response && (size > 0)) {
843 /* Coords Result GList */
844 GList *placeList = NULL;
846 MAP_DEBUG("Search Places Details :- Parsing Json Response");
847 __parse_place_response(response, size, &placeList);
849 if (placeList != NULL) {
850 /* Put the response in queue */
851 responseData->error = MAPZEN_ERROR_NONE;
852 responseData->places = placeList;
854 /* REPSONSE PARSING FAILURE */
855 MAP_DEBUG("addr Response is NULL");
856 responseData->error = MAPZEN_ERROR_UNKNOWN;
857 responseData->places = NULL;
860 responseData->error = MAPZEN_ERROR_UNKNOWN;
861 responseData->places = NULL;
864 mapzen_push_to_queue(type, (gpointer)responseData);
874 case RESP_TYPE_PLACES_LIST:
876 MAP_DEBUG("Inside Places List JSON Parsing..");
877 MapzenPlaceListQueryData *queryData = (MapzenPlaceListQueryData *)user_data;
878 MapzenPlaceListResponseData *responseData = (MapzenPlaceListResponseData *)g_malloc(sizeof(MapzenPlaceListResponseData));
881 responseData->requestId = queryData->requestId;
882 responseData->place_list_search_cb = queryData->place_list_search_cb;
883 responseData->user_data = queryData->user_data;
885 if (response && (size > 0)) {
886 /* Coords Result GList */
887 GList *placeList = NULL;
889 MAP_DEBUG("Search Places :- Parsing Json Response");
890 __parse_place_response(response, size, &placeList);
892 if (placeList != NULL) {
893 /* Put the response in queue */
894 responseData->error = MAPZEN_ERROR_NONE;
895 responseData->places = placeList;
897 /* REPSONSE PARSING FAILURE */
898 MAP_DEBUG("addr Response is NULL");
899 responseData->error = MAPZEN_ERROR_UNKNOWN;
900 responseData->places = NULL;
903 responseData->error = MAPZEN_ERROR_UNKNOWN;
904 responseData->places = NULL;
907 mapzen_push_to_queue(type, (gpointer)responseData);
917 case RESP_TYPE_ROUTE:
919 MAP_DEBUG(">>>>> RESP_TYPE_ROUTE");
921 MapzenRouteQueryData *queryData = (MapzenRouteQueryData *)user_data;
922 MAP_DEBUG(">>>>> PROCESS post_curl_response set the following: __route_unit and __route_type");
923 __route_unit = queryData->unit;
924 __route_type = queryData->type;
925 MAP_DEBUG(">>>>> PROCESS post_curl_response __route_unit=%d", __route_unit);
926 MAP_DEBUG(">>>>> PROCESS post_curl_response __route_type=%d", __route_type);
928 MAP_DEBUG(">>>>> PROCESS post_curl_response: prepare MapzenRouteResponseData");
929 MapzenRouteResponseData *responseData = (MapzenRouteResponseData *)g_malloc(sizeof(MapzenRouteResponseData));
932 responseData->requestId = queryData->requestId;
933 responseData->route_cb = queryData->route_cb;
934 responseData->user_data = queryData->user_data;
936 if (response && (size > 0)) {
937 /* Coords Result GList */
938 mapzen_route_resp_s *routeResponse = NULL;
940 MAP_DEBUG(">>>>> PROCESS post_curl_response: PRE __parse_route_response");
941 __parse_route_response(response, size, &status, &routeResponse);
942 MAP_DEBUG(">>>>> PROCESS post_curl_response: POST __parse_route_response");
944 if (routeResponse != NULL) {
945 MAP_DEBUG(">>>>> PROCESS post_curl_response: (routeResponse != NULL)");
946 MAP_DEBUG(">>>>> PROCESS post_curl_response: status=%d", status);
947 MAP_DEBUG(">>>>> PROCESS post_curl_response: __convert_status(status)=%d", __convert_status(status));
948 /* Put the response in queue */
949 responseData->error = __convert_status(status);
950 responseData->routeResponse = routeResponse;
952 /* REPSONSE PARSING FAILURE */
953 MAP_DEBUG(">>>>> PROCESS post_curl_response: routeResponse is NULL");
954 responseData->error = __convert_status(status);
955 responseData->routeResponse = NULL;
958 MAP_DEBUG(">>>>> PROCESS post_curl_response: JSON response is NULL");
959 responseData->error = __convert_status(status);
960 responseData->routeResponse = NULL;
963 MAP_DEBUG(">>>>> PROCESS post_curl_response: PRE mapzen_push_to_queue");
964 mapzen_push_to_queue(type, (gpointer)responseData);
965 MAP_DEBUG(">>>>> PROCESS post_curl_response: POST mapzen_push_to_queue");
977 MAP_DEBUG("Inside default JSON Parsing..");
981 MAP_DEBUG(">>>>> END post_curl_response");