~valhalla-routing/+junk/valhalla_2.1.9-0ubuntu1

« back to all changes in this revision

Viewing changes to libvalhalla/src/thor/trace_attributes_action.cc

  • Committer: valhalla
  • Date: 2017-04-24 20:20:53 UTC
  • Revision ID: valhalla@mapzen.com-20170424202053-7o69b9nwx9ee0tw3
Packaging for 2.1.9-0ubuntu1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <prime_server/prime_server.hpp>
 
2
 
 
3
using namespace prime_server;
 
4
 
 
5
#include <algorithm>
 
6
#include <utility>
 
7
#include <string>
 
8
#include <vector>
 
9
 
 
10
#include <boost/property_tree/ptree.hpp>
 
11
#include <boost/property_tree/json_parser.hpp>
 
12
 
 
13
#include "baldr/json.h"
 
14
#include "baldr/graphconstants.h"
 
15
#include "baldr/directededge.h"
 
16
#include "midgard/logging.h"
 
17
#include "midgard/constants.h"
 
18
#include "baldr/errorcode_util.h"
 
19
#include "odin/util.h"
 
20
#include "odin/enhancedtrippath.h"
 
21
#include "proto/tripdirections.pb.h"
 
22
#include "proto/trippath.pb.h"
 
23
 
 
24
#include "thor/service.h"
 
25
#include "thor/attributes_controller.h"
 
26
#include "thor/match_result.h"
 
27
 
 
28
using namespace valhalla;
 
29
using namespace valhalla::midgard;
 
30
using namespace valhalla::baldr;
 
31
using namespace valhalla::sif;
 
32
using namespace valhalla::odin;
 
33
using namespace valhalla::thor;
 
34
 
 
35
 
 
36
namespace {
 
37
  const headers_t::value_type CORS { "Access-Control-Allow-Origin", "*" };
 
38
  const headers_t::value_type JSON_MIME { "Content-type", "application/json;charset=utf-8" };
 
39
  const headers_t::value_type JS_MIME { "Content-type", "application/javascript;charset=utf-8" };
 
40
 
 
41
  json::MapPtr serialize(const AttributesController& controller,
 
42
      const valhalla::odin::TripPath& trip_path,
 
43
      const boost::optional<std::string>& id,
 
44
      const DirectionsOptions& directions_options,
 
45
      const std::vector<thor::MatchResult>& match_results) {
 
46
    // Length and speed default to kilometers
 
47
    double scale = 1;
 
48
    if (directions_options.has_units()
 
49
        && directions_options.units() == DirectionsOptions::kMiles) {
 
50
      scale = kMilePerKm;
 
51
    }
 
52
 
 
53
    // Loop over edges to add attributes
 
54
    json::ArrayPtr edge_array = json::array({});
 
55
    for (int i = 1; i < trip_path.node().size(); i++) {
 
56
 
 
57
      if (trip_path.node(i-1).has_edge()) {
 
58
        const auto& edge = trip_path.node(i - 1).edge();
 
59
 
 
60
        // Process each edge
 
61
        auto edge_map = json::map({});
 
62
        if (edge.has_truck_route())
 
63
          edge_map->emplace("truck_route", static_cast<bool>(edge.truck_route()));
 
64
        if (edge.has_truck_speed() && (edge.truck_speed() > 0))
 
65
          edge_map->emplace("truck_speed", static_cast<uint64_t>(std::round(edge.truck_speed() * scale)));
 
66
        if (edge.has_speed_limit() && (edge.speed_limit() > 0))
 
67
          edge_map->emplace("speed_limit", static_cast<uint64_t>(std::round(edge.speed_limit() * scale)));
 
68
        if (edge.has_density())
 
69
          edge_map->emplace("density", static_cast<uint64_t>(edge.density()));
 
70
        if (edge.has_sidewalk())
 
71
          edge_map->emplace("sidewalk", to_string(edge.sidewalk()));
 
72
        if (edge.has_bicycle_network())
 
73
          edge_map->emplace("bicycle_network", static_cast<uint64_t>(edge.bicycle_network()));
 
74
        if (edge.has_cycle_lane())
 
75
          edge_map->emplace("cycle_lane", to_string(static_cast<CycleLane>(edge.cycle_lane())));
 
76
        if (edge.has_lane_count())
 
77
          edge_map->emplace("lane_count", static_cast<uint64_t>(edge.lane_count()));
 
78
        if (edge.lane_connectivity_size()) {
 
79
          auto lane_connectivity = json::array({});
 
80
          for (const auto& l : edge.lane_connectivity()) {
 
81
            auto element = json::map({});
 
82
            element->emplace("from", l.from_way_id());
 
83
            element->emplace("to_lanes", l.to_lanes());
 
84
            element->emplace("from_lanes", l.from_lanes());
 
85
            lane_connectivity->push_back(element);
 
86
          }
 
87
          edge_map->emplace("lane_connectivity", lane_connectivity);
 
88
        }
 
89
        if (edge.has_max_downward_grade())
 
90
          edge_map->emplace("max_downward_grade", static_cast<int64_t>(edge.max_downward_grade()));
 
91
        if (edge.has_max_upward_grade())
 
92
          edge_map->emplace("max_upward_grade", static_cast<int64_t>(edge.max_upward_grade()));
 
93
        if (edge.has_weighted_grade())
 
94
          edge_map->emplace("weighted_grade", json::fp_t{edge.weighted_grade(), 3});
 
95
        if (edge.has_mean_elevation()) {
 
96
          // Convert to feet if a valid elevation and units are miles
 
97
          float mean = edge.mean_elevation();
 
98
          if (mean != kNoElevationData && directions_options.has_units()
 
99
              && directions_options.units() == DirectionsOptions::kMiles) {
 
100
            mean *= kFeetPerMeter;
 
101
          }
 
102
          edge_map->emplace("mean_elevation", static_cast<int64_t>(mean));
 
103
        }
 
104
        if (edge.has_way_id())
 
105
          edge_map->emplace("way_id", static_cast<uint64_t>(edge.way_id()));
 
106
        if (edge.has_id())
 
107
          edge_map->emplace("id", static_cast<uint64_t>(edge.id()));
 
108
        if (edge.has_travel_mode())
 
109
          edge_map->emplace("travel_mode", to_string(edge.travel_mode()));
 
110
        if (edge.has_vehicle_type())
 
111
          edge_map->emplace("vehicle_type", to_string(edge.vehicle_type()));
 
112
        if (edge.has_pedestrian_type())
 
113
          edge_map->emplace("pedestrian_type", to_string(edge.pedestrian_type()));
 
114
        if (edge.has_bicycle_type())
 
115
          edge_map->emplace("bicycle_type", to_string(edge.bicycle_type()));
 
116
        if (edge.has_surface())
 
117
          edge_map->emplace("surface", to_string(static_cast<baldr::Surface>(edge.surface())));
 
118
        if (edge.has_drive_on_right())
 
119
          edge_map->emplace("drive_on_right", static_cast<bool>(edge.drive_on_right()));
 
120
        if (edge.has_internal_intersection())
 
121
          edge_map->emplace("internal_intersection", static_cast<bool>(edge.internal_intersection()));
 
122
        if (edge.has_roundabout())
 
123
          edge_map->emplace("roundabout", static_cast<bool>(edge.roundabout()));
 
124
        if (edge.has_bridge())
 
125
          edge_map->emplace("bridge", static_cast<bool>(edge.bridge()));
 
126
        if (edge.has_tunnel())
 
127
          edge_map->emplace("tunnel", static_cast<bool>(edge.tunnel()));
 
128
        if (edge.has_unpaved())
 
129
          edge_map->emplace("unpaved", static_cast<bool>(edge.unpaved()));
 
130
        if (edge.has_toll())
 
131
            edge_map->emplace("toll", static_cast<bool>(edge.toll()));
 
132
       if (edge.has_use())
 
133
          edge_map->emplace("use", to_string(static_cast<baldr::Use>(edge.use())));
 
134
        if (edge.has_traversability())
 
135
          edge_map->emplace("traversability", to_string(edge.traversability()));
 
136
        if (edge.has_end_shape_index())
 
137
          edge_map->emplace("end_shape_index", static_cast<uint64_t>(edge.end_shape_index()));
 
138
        if (edge.has_begin_shape_index())
 
139
          edge_map->emplace("begin_shape_index", static_cast<uint64_t>(edge.begin_shape_index()));
 
140
        if (edge.has_end_heading())
 
141
          edge_map->emplace("end_heading", static_cast<uint64_t>(edge.end_heading()));
 
142
        if (edge.has_begin_heading())
 
143
          edge_map->emplace("begin_heading", static_cast<uint64_t>(edge.begin_heading()));
 
144
        if (edge.has_road_class())
 
145
          edge_map->emplace("road_class", to_string(static_cast<baldr::RoadClass>(edge.road_class())));
 
146
        if (edge.has_speed())
 
147
          edge_map->emplace("speed", static_cast<uint64_t>(std::round(edge.speed() * scale)));
 
148
        if (edge.has_length())
 
149
          edge_map->emplace("length", json::fp_t{edge.length() * scale, 3});
 
150
        if (edge.name_size() > 0) {
 
151
          auto names_array = json::array({});
 
152
          for (const auto& name : edge.name())
 
153
            names_array->push_back(name);
 
154
          edge_map->emplace("names", names_array);
 
155
        }
 
156
 
 
157
        // Process edge sign
 
158
        if (edge.has_sign()) {
 
159
          auto sign_map = json::map({});
 
160
 
 
161
          // Populate exit number array
 
162
          if (edge.sign().exit_number_size() > 0) {
 
163
            auto exit_number_array = json::array({});
 
164
            for (const auto& exit_number : edge.sign().exit_number()) {
 
165
              exit_number_array->push_back(exit_number);
 
166
            }
 
167
            sign_map->emplace("exit_number", exit_number_array);
 
168
          }
 
169
 
 
170
          // Populate exit branch array
 
171
          if (edge.sign().exit_branch_size() > 0) {
 
172
            auto exit_branch_array = json::array({});
 
173
            for (const auto& exit_branch : edge.sign().exit_branch()) {
 
174
              exit_branch_array->push_back(exit_branch);
 
175
            }
 
176
            sign_map->emplace("exit_branch", exit_branch_array);
 
177
          }
 
178
 
 
179
          // Populate exit toward array
 
180
          if (edge.sign().exit_toward_size() > 0) {
 
181
            auto exit_toward_array = json::array({});
 
182
            for (const auto& exit_toward : edge.sign().exit_toward()) {
 
183
              exit_toward_array->push_back(exit_toward);
 
184
            }
 
185
            sign_map->emplace("exit_toward", exit_toward_array);
 
186
          }
 
187
 
 
188
          // Populate exit name array
 
189
          if (edge.sign().exit_name_size() > 0) {
 
190
            auto exit_name_array = json::array({});
 
191
            for (const auto& exit_name : edge.sign().exit_name()) {
 
192
              exit_name_array->push_back(exit_name);
 
193
            }
 
194
            sign_map->emplace("exit_name", exit_name_array);
 
195
          }
 
196
 
 
197
          edge_map->emplace("sign", sign_map);
 
198
        }
 
199
 
 
200
        // Process edge end node only if any node items are enabled
 
201
        if (controller.category_attribute_enabled(kNodeCategory)) {
 
202
          const auto& node = trip_path.node(i);
 
203
          auto end_node_map = json::map({});
 
204
 
 
205
          if (node.intersecting_edge_size() > 0) {
 
206
            auto intersecting_edge_array = json::array({});
 
207
            for (const auto& xedge : node.intersecting_edge()) {
 
208
              auto xedge_map = json::map({});
 
209
              if (xedge.has_walkability() && (xedge.walkability() != TripPath_Traversability_kNone))
 
210
                xedge_map->emplace("walkability", to_string(xedge.walkability()));
 
211
              if (xedge.has_cyclability() && (xedge.cyclability() != TripPath_Traversability_kNone))
 
212
                xedge_map->emplace("cyclability", to_string(xedge.cyclability()));
 
213
              if (xedge.has_driveability() && (xedge.driveability() != TripPath_Traversability_kNone))
 
214
                xedge_map->emplace("driveability", to_string(xedge.driveability()));
 
215
              xedge_map->emplace("from_edge_name_consistency", static_cast<bool>(xedge.prev_name_consistency()));
 
216
              xedge_map->emplace("to_edge_name_consistency", static_cast<bool>(xedge.curr_name_consistency()));
 
217
              xedge_map->emplace("begin_heading", static_cast<uint64_t>(xedge.begin_heading()));
 
218
 
 
219
              intersecting_edge_array->emplace_back(xedge_map);
 
220
            }
 
221
            end_node_map->emplace("intersecting_edges", intersecting_edge_array);
 
222
          }
 
223
 
 
224
          if (node.has_elapsed_time())
 
225
            end_node_map->emplace("elapsed_time", static_cast<uint64_t>(node.elapsed_time()));
 
226
          if (node.has_admin_index())
 
227
            end_node_map->emplace("admin_index", static_cast<uint64_t>(node.admin_index()));
 
228
          if (node.has_type())
 
229
            end_node_map->emplace("type", to_string(static_cast<baldr::NodeType>(node.type())));
 
230
          if (node.has_fork())
 
231
            end_node_map->emplace("fork", static_cast<bool>(node.fork()));
 
232
          if (node.has_time_zone())
 
233
            end_node_map->emplace("time_zone", node.time_zone());
 
234
 
 
235
          // TODO transit info at node
 
236
          // kNodeTransitStopInfoType = "node.transit_stop_info.type";
 
237
          // kNodeTransitStopInfoOnestopId = "node.transit_stop_info.onestop_id";
 
238
          // kNodetransitStopInfoName = "node.transit_stop_info.name";
 
239
          // kNodeTransitStopInfoArrivalDateTime = "node.transit_stop_info.arrival_date_time";
 
240
          // kNodeTransitStopInfoDepartureDateTime = "node.transit_stop_info.departure_date_time";
 
241
          // kNodeTransitStopInfoIsParentStop = "node.transit_stop_info.is_parent_stop";
 
242
          // kNodeTransitStopInfoAssumedSchedule = "node.transit_stop_info.assumed_schedule";
 
243
          // kNodeTransitStopInfoLatLon = "node.transit_stop_info.lat_lon";
 
244
 
 
245
          edge_map->emplace("end_node", end_node_map);
 
246
        }
 
247
 
 
248
        // TODO - transit info on edge
 
249
        // kEdgeTransitType = "edge.transit_type";
 
250
        // kEdgeTransitRouteInfoOnestopId = "edge.transit_route_info.onestop_id";
 
251
        // kEdgeTransitRouteInfoBlockId = "edge.transit_route_info.block_id";
 
252
        // kEdgeTransitRouteInfoTripId = "edge.transit_route_info.trip_id";
 
253
        // kEdgeTransitRouteInfoShortName = "edge.transit_route_info.short_name";
 
254
        // kEdgeTransitRouteInfoLongName = "edge.transit_route_info.long_name";
 
255
        // kEdgeTransitRouteInfoHeadsign = "edge.transit_route_info.headsign";
 
256
        // kEdgeTransitRouteInfoColor = "edge.transit_route_info.color";
 
257
        // kEdgeTransitRouteInfoTextColor = "edge.transit_route_info.text_color";
 
258
        // kEdgeTransitRouteInfoDescription = "edge.transit_route_info.description";
 
259
        // kEdgeTransitRouteInfoOperatorOnestopId = "edge.transit_route_info.operator_onestop_id";
 
260
        // kEdgeTransitRouteInfoOperatorName = "edge.transit_route_info.operator_name";
 
261
        // kEdgeTransitRouteInfoOperatorUrl = "edge.transit_route_info.operator_url";
 
262
 
 
263
        edge_array->emplace_back(edge_map);
 
264
      }
 
265
    }
 
266
 
 
267
    // Add edge array
 
268
    auto json = json::map({
 
269
      {"edges", edge_array}
 
270
    });
 
271
 
 
272
    // Add result id, if supplied
 
273
    if (id)
 
274
      json->emplace("id", *id);
 
275
 
 
276
    // Add shape
 
277
    if (trip_path.has_shape())
 
278
      json->emplace("shape", trip_path.shape());
 
279
 
 
280
    // Add matched points, if requested
 
281
    if (controller.category_attribute_enabled(kMatchedCategory)
 
282
        && !match_results.empty()) {
 
283
      auto match_points_array = json::array({});
 
284
      for (const auto& match_result : match_results) {
 
285
        auto match_points_map = json::map({});
 
286
 
 
287
        // Process matched point
 
288
        if (controller.attributes.at(kMatchedPoint)) {
 
289
          match_points_map->emplace("lon", json::fp_t{match_result.lnglat.first,6});
 
290
          match_points_map->emplace("lat", json::fp_t{match_result.lnglat.second,6});
 
291
        }
 
292
 
 
293
        // Process matched type
 
294
        if (controller.attributes.at(kMatchedType)) {
 
295
          switch (match_result.type) {
 
296
            case thor::MatchResult::Type::kMatched:
 
297
              match_points_map->emplace("type", std::string("matched"));
 
298
              break;
 
299
            case thor::MatchResult::Type::kInterpolated:
 
300
              match_points_map->emplace("type", std::string("interpolated"));
 
301
              break;
 
302
            default:
 
303
              match_points_map->emplace("type", std::string("unmatched"));
 
304
              break;
 
305
          }
 
306
        }
 
307
 
 
308
        // Process matched point edge index
 
309
        if (controller.attributes.at(kMatchedEdgeIndex) && match_result.HasEdgeIndex())
 
310
          match_points_map->emplace("edge_index", static_cast<uint64_t>(match_result.edge_index));
 
311
 
 
312
        // Process matched point distance along edge
 
313
        if (controller.attributes.at(kMatchedDistanceAlongEdge))
 
314
          match_points_map->emplace("distance_along_edge", json::fp_t{match_result.distance_along,3});
 
315
 
 
316
        // Process matched point distance from trace point
 
317
        if (controller.attributes.at(kMatchedDistanceFromTracePoint))
 
318
          match_points_map->emplace("distance_from_trace_point", json::fp_t{match_result.distance_from,3});
 
319
 
 
320
        match_points_array->push_back(match_points_map);
 
321
      }
 
322
      json->emplace("matched_points", match_points_array);
 
323
    }
 
324
 
 
325
    // Add osm_changeset
 
326
    if (trip_path.has_osm_changeset())
 
327
      json->emplace("osm_changeset", trip_path.osm_changeset());
 
328
 
 
329
    // Add admins list
 
330
    if (trip_path.admin_size() > 0) {
 
331
      auto admin_array = json::array({});
 
332
      for (const auto& admin : trip_path.admin()) {
 
333
        auto admin_map = json::map({});
 
334
        if (admin.has_country_code())
 
335
          admin_map->emplace("country_code", admin.country_code());
 
336
        if (admin.has_country_text())
 
337
          admin_map->emplace("country_text", admin.country_text());
 
338
        if (admin.has_state_code())
 
339
          admin_map->emplace("state_code", admin.state_code());
 
340
        if (admin.has_state_text())
 
341
          admin_map->emplace("state_text", admin.state_text());
 
342
 
 
343
        admin_array->push_back(admin_map);
 
344
      }
 
345
      json->emplace("admins", admin_array);
 
346
    }
 
347
 
 
348
    // Add units, if specified
 
349
    if (directions_options.has_units()) {
 
350
      json->emplace("units", std::string(
 
351
        (directions_options.units() == valhalla::odin::DirectionsOptions::kKilometers)
 
352
          ? "kilometers" : "miles"));
 
353
    }
 
354
 
 
355
    return json;
 
356
  }
 
357
 
 
358
}
 
359
 
 
360
namespace valhalla {
 
361
namespace thor {
 
362
 
 
363
void thor_worker_t::filter_attributes(const boost::property_tree::ptree& request, AttributesController& controller) {
 
364
  std::string filter_action = request.get("filters.action", "");
 
365
 
 
366
  if (filter_action.size() && filter_action == "include") {
 
367
    controller.disable_all();
 
368
    for (const auto& kv : request.get_child("filters.attributes"))
 
369
      controller.attributes.at(kv.second.get_value<std::string>()) = true;
 
370
 
 
371
  } else if (filter_action.size() && filter_action == "exclude") {
 
372
    controller.enable_all();
 
373
    for (const auto& kv : request.get_child("filters.attributes"))
 
374
      controller.attributes.at(kv.second.get_value<std::string>()) = false;
 
375
 
 
376
  } else {
 
377
    controller.enable_all();
 
378
  }
 
379
}
 
380
 
 
381
/*
 
382
 * The trace_attributes action takes a GPS trace or latitude, longitude positions
 
383
 * from a portion of an existing route and returns detailed attribution along the
 
384
 * portion of the route. This includes details for each section of road along the
 
385
 * path as well as any intersections along the path.
 
386
 */
 
387
worker_t::result_t thor_worker_t::trace_attributes(
 
388
    const boost::property_tree::ptree &request,
 
389
    const std::string &request_str, http_request_info_t& request_info) {
 
390
  //get time for start of request
 
391
  auto s = std::chrono::system_clock::now();
 
392
 
 
393
  // Parse request
 
394
  parse_locations(request);
 
395
  parse_shape(request);
 
396
  parse_costing(request);
 
397
  parse_trace_config(request);
 
398
  /*
 
399
   * A flag indicating whether the input shape is a GPS trace or exact points from a
 
400
   * prior route run against the Valhalla road network.  Knowing that the input is from
 
401
   * Valhalla will allow an efficient “edge-walking” algorithm rather than a more extensive
 
402
   * map-matching method. If true, this enforces to only use exact route match algorithm.
 
403
   */
 
404
  odin::TripPath trip_path;
 
405
  std::vector<thor::MatchResult> match_results;
 
406
  std::pair<odin::TripPath, std::vector<thor::MatchResult>> trip_match;
 
407
  AttributesController controller;
 
408
  filter_attributes(request, controller);
 
409
  auto shape_match = STRING_TO_MATCH.find(request.get<std::string>("shape_match", "walk_or_snap"));
 
410
  if (shape_match == STRING_TO_MATCH.cend())
 
411
    throw valhalla_exception_t{400, 445};
 
412
  else {
 
413
    // If the exact points from a prior route that was run against the Valhalla road network,
 
414
    // then we can traverse the exact shape to form a path by using edge-walking algorithm
 
415
    switch (shape_match->second) {
 
416
      case EDGE_WALK:
 
417
        try {
 
418
          trip_path = route_match(controller);
 
419
          if (trip_path.node().size() == 0)
 
420
            throw valhalla_exception_t{400, 443};
 
421
        } catch (const valhalla_exception_t& e) {
 
422
          throw valhalla_exception_t{400, 443, shape_match->first + " algorithm failed to find exact route match.  Try using shape_match:'walk_or_snap' to fallback to map-matching algorithm"};
 
423
        }
 
424
        break;
 
425
      // If non-exact shape points are used, then we need to correct this shape by sending them
 
426
      // through the map-matching algorithm to snap the points to the correct shape
 
427
      case MAP_SNAP:
 
428
        try {
 
429
          trip_match = map_match(controller, true);
 
430
          trip_path = std::move(trip_match.first);
 
431
          match_results = std::move(trip_match.second);
 
432
        } catch (const valhalla_exception_t& e) {
 
433
          throw valhalla_exception_t{400, 444, shape_match->first + " algorithm failed to snap the shape points to the correct shape."};
 
434
        }
 
435
        break;
 
436
      //If we think that we have the exact shape but there ends up being no Valhalla route match, then
 
437
      // then we want to fallback to try and use meili map matching to match to local route network.
 
438
      //No shortcuts are used and detailed information at every intersection becomes available.
 
439
      case WALK_OR_SNAP:
 
440
        trip_path = route_match(controller);
 
441
        if (trip_path.node().size() == 0) {
 
442
          LOG_WARN(shape_match->first + " algorithm failed to find exact route match; Falling back to map_match...");
 
443
          try {
 
444
            trip_match = map_match(controller, true);
 
445
            trip_path = std::move(trip_match.first);
 
446
            match_results = std::move(trip_match.second);
 
447
          } catch (const valhalla_exception_t& e) {
 
448
            throw valhalla_exception_t{400, 444, shape_match->first + " algorithm failed to snap the shape points to the correct shape."};
 
449
          }
 
450
        }
 
451
        break;
 
452
      }
 
453
    }
 
454
 
 
455
  auto id = request.get_optional<std::string>("id");
 
456
  // Get the directions_options if they are in the request
 
457
  DirectionsOptions directions_options;
 
458
  auto options = request.get_child_optional("directions_options");
 
459
  if(options)
 
460
    directions_options = valhalla::odin::GetDirectionsOptions(*options);
 
461
 
 
462
  //serialize output to Thor
 
463
  json::MapPtr json;
 
464
  if (trip_path.node().size() > 0)
 
465
    json = serialize(controller, trip_path, id, directions_options, match_results);
 
466
  else throw valhalla_exception_t{400, 442};
 
467
 
 
468
  //jsonp callback if need be
 
469
  std::ostringstream stream;
 
470
  auto jsonp = request.get_optional<std::string>("jsonp");
 
471
  if (jsonp)
 
472
    stream << *jsonp << '(';
 
473
  stream << *json;
 
474
  if (jsonp)
 
475
    stream << ')';
 
476
 
 
477
  // Get processing time for thor
 
478
  auto e = std::chrono::system_clock::now();
 
479
  std::chrono::duration<float, std::milli> elapsed_time = e - s;
 
480
  //log request if greater than X (ms)
 
481
  if (!healthcheck && !request_info.spare && (elapsed_time.count() / shape.size()) > (long_request / 1100)) {
 
482
    LOG_WARN("thor::trace_attributes elapsed time (ms)::"+ std::to_string(elapsed_time.count()));
 
483
    LOG_WARN("thor::trace_attributes exceeded threshold::"+ request_str);
 
484
    midgard::logging::Log("valhalla_thor_long_request_trace_attributes", " [ANALYTICS] ");
 
485
  }
 
486
  http_response_t response(200, "OK", stream.str(), headers_t{CORS, jsonp ? JS_MIME : JSON_MIME});
 
487
  response.from_info(request_info);
 
488
  worker_t::result_t result{false};
 
489
  result.messages.emplace_back(response.to_string());
 
490
  return result;
 
491
}
 
492
}
 
493
}