First step into overhauling the edge storage
This commit is contained in:
parent
c493a22765
commit
a57fb4f1ab
@ -329,7 +329,7 @@ if(WITH_TOOLS OR BUILD_TOOLS)
|
|||||||
target_link_libraries(osrm-unlock-all rt)
|
target_link_libraries(osrm-unlock-all rt)
|
||||||
endif()
|
endif()
|
||||||
add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:IMPORT>)
|
add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:IMPORT>)
|
||||||
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
|
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES} ${TBB_LIBRARIES})
|
||||||
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
|
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
|
||||||
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
|
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ int Prepare::Run()
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
|
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
|
||||||
#else
|
#else
|
||||||
static_assert(sizeof(ImportEdge) == 20,
|
static_assert(sizeof(NodeBasedEdge) == 20,
|
||||||
"changing ImportEdge type has influence on memory consumption!");
|
"changing NodeBasedEdge type has influence on memory consumption!");
|
||||||
static_assert(sizeof(EdgeBasedEdge) == 16,
|
static_assert(sizeof(EdgeBasedEdge) == 16,
|
||||||
"changing EdgeBasedEdge type has influence on memory consumption!");
|
"changing EdgeBasedEdge type has influence on memory consumption!");
|
||||||
#endif
|
#endif
|
||||||
@ -325,7 +325,7 @@ Prepare::LoadNodeBasedGraph(std::vector<NodeID> &barrier_node_list,
|
|||||||
RestrictionMap &restriction_map,
|
RestrictionMap &restriction_map,
|
||||||
std::vector<QueryNode>& internal_to_external_node_map)
|
std::vector<QueryNode>& internal_to_external_node_map)
|
||||||
{
|
{
|
||||||
std::vector<ImportEdge> edge_list;
|
std::vector<NodeBasedEdge> edge_list;
|
||||||
std::unordered_map<NodeID, NodeID> external_to_internal_node_map;
|
std::unordered_map<NodeID, NodeID> external_to_internal_node_map;
|
||||||
|
|
||||||
boost::filesystem::ifstream input_stream(config.osrm_input_path, std::ios::in | std::ios::binary);
|
boost::filesystem::ifstream input_stream(config.osrm_input_path, std::ios::in | std::ios::binary);
|
||||||
|
@ -86,6 +86,4 @@ struct EdgeBasedEdge
|
|||||||
bool backward : 1;
|
bool backward : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ImportEdge = NodeBasedEdge;
|
|
||||||
|
|
||||||
#endif /* IMPORT_EDGE_HPP */
|
#endif /* IMPORT_EDGE_HPP */
|
||||||
|
@ -74,16 +74,16 @@ struct NodeBasedEdgeData
|
|||||||
|
|
||||||
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
|
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
|
||||||
|
|
||||||
// Factory method to create NodeBasedDynamicGraph from ImportEdges
|
// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
|
||||||
inline std::shared_ptr<NodeBasedDynamicGraph>
|
inline std::shared_ptr<NodeBasedDynamicGraph>
|
||||||
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
|
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<NodeBasedEdge> &input_edge_list)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(NodeBasedEdgeData) == 16,
|
static_assert(sizeof(NodeBasedEdgeData) == 16,
|
||||||
"changing node based edge data size changes memory consumption");
|
"changing node based edge data size changes memory consumption");
|
||||||
|
|
||||||
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
|
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
|
||||||
NodeBasedDynamicGraph::InputEdge edge;
|
NodeBasedDynamicGraph::InputEdge edge;
|
||||||
for (const ImportEdge &import_edge : input_edge_list)
|
for (const NodeBasedEdge &import_edge : input_edge_list)
|
||||||
{
|
{
|
||||||
if (import_edge.forward)
|
if (import_edge.forward)
|
||||||
{
|
{
|
||||||
|
@ -54,6 +54,7 @@ ExtractionContainers::ExtractionContainers()
|
|||||||
|
|
||||||
ExtractionContainers::~ExtractionContainers()
|
ExtractionContainers::~ExtractionContainers()
|
||||||
{
|
{
|
||||||
|
// FIXME isn't this done implicitly of the stxxl::vectors go out of scope?
|
||||||
used_node_id_list.clear();
|
used_node_id_list.clear();
|
||||||
all_nodes_list.clear();
|
all_nodes_list.clear();
|
||||||
all_edges_list.clear();
|
all_edges_list.clear();
|
||||||
@ -71,394 +72,383 @@ ExtractionContainers::~ExtractionContainers()
|
|||||||
* - filter nodes list to nodes that are referenced by ways
|
* - filter nodes list to nodes that are referenced by ways
|
||||||
* - merge edges with nodes to include location of start/end points and serialize
|
* - merge edges with nodes to include location of start/end points and serialize
|
||||||
*
|
*
|
||||||
* FIXME: Each of this step should be an own function for readability.
|
|
||||||
*/
|
*/
|
||||||
void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
void ExtractionContainers::PrepareData(const std::string &output_file_name,
|
||||||
const std::string &restrictions_file_name)
|
const std::string &restrictions_file_name,
|
||||||
|
const std::string &name_file_name)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
unsigned number_of_used_nodes = 0;
|
|
||||||
unsigned number_of_used_edges = 0;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
PrepareRestrictions();
|
||||||
TIMER_START(sorting_used_nodes);
|
WriteRestrictions(restrictions_file_name);
|
||||||
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
|
|
||||||
TIMER_STOP(sorting_used_nodes);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
|
||||||
TIMER_START(erasing_dups);
|
|
||||||
auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
|
|
||||||
used_node_id_list.resize(new_end - used_node_id_list.begin());
|
|
||||||
TIMER_STOP(erasing_dups);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
|
||||||
TIMER_START(sorting_nodes);
|
|
||||||
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
|
|
||||||
stxxl_memory);
|
|
||||||
TIMER_STOP(sorting_nodes);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
|
||||||
TIMER_START(sort_ways);
|
|
||||||
stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
|
|
||||||
FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
|
|
||||||
TIMER_STOP(sort_ways);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Sorting " << restrictions_list.size()
|
|
||||||
<< " restrictions. by from... " << std::flush;
|
|
||||||
TIMER_START(sort_restrictions);
|
|
||||||
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
|
|
||||||
CmpRestrictionContainerByFrom(), stxxl_memory);
|
|
||||||
TIMER_STOP(sort_restrictions);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
|
||||||
TIMER_START(fix_restriction_starts);
|
|
||||||
auto restrictions_iterator = restrictions_list.begin();
|
|
||||||
auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
|
|
||||||
|
|
||||||
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
|
|
||||||
restrictions_iterator != restrictions_list.end())
|
|
||||||
{
|
|
||||||
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
|
|
||||||
{
|
|
||||||
++way_start_and_end_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
|
|
||||||
{
|
|
||||||
++restrictions_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
|
|
||||||
restrictions_iterator->restriction.from.way);
|
|
||||||
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
|
|
||||||
|
|
||||||
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
|
|
||||||
{
|
|
||||||
restrictions_iterator->restriction.from.node =
|
|
||||||
way_start_and_end_iterator->first_segment_target_id;
|
|
||||||
}
|
|
||||||
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
|
|
||||||
{
|
|
||||||
restrictions_iterator->restriction.from.node =
|
|
||||||
way_start_and_end_iterator->last_segment_source_id;
|
|
||||||
}
|
|
||||||
++restrictions_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_STOP(fix_restriction_starts);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
|
|
||||||
TIMER_START(sort_restrictions_to);
|
|
||||||
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
|
|
||||||
CmpRestrictionContainerByTo(), stxxl_memory);
|
|
||||||
TIMER_STOP(sort_restrictions_to);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
|
||||||
TIMER_START(fix_restriction_ends);
|
|
||||||
restrictions_iterator = restrictions_list.begin();
|
|
||||||
way_start_and_end_iterator = way_start_end_id_list.cbegin();
|
|
||||||
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
|
|
||||||
restrictions_iterator != restrictions_list.end())
|
|
||||||
{
|
|
||||||
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
|
|
||||||
{
|
|
||||||
++way_start_and_end_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
|
|
||||||
{
|
|
||||||
++restrictions_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
|
|
||||||
restrictions_iterator->restriction.to.way);
|
|
||||||
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
|
|
||||||
|
|
||||||
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
|
|
||||||
{
|
|
||||||
restrictions_iterator->restriction.to.node =
|
|
||||||
way_start_and_end_iterator->first_segment_target_id;
|
|
||||||
}
|
|
||||||
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
|
|
||||||
{
|
|
||||||
restrictions_iterator->restriction.to.node =
|
|
||||||
way_start_and_end_iterator->last_segment_source_id;
|
|
||||||
}
|
|
||||||
++restrictions_iterator;
|
|
||||||
}
|
|
||||||
TIMER_STOP(fix_restriction_ends);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
|
|
||||||
|
|
||||||
// serialize restrictions
|
|
||||||
std::ofstream restrictions_out_stream;
|
|
||||||
unsigned written_restriction_count = 0;
|
|
||||||
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
|
|
||||||
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
|
||||||
const auto count_position = restrictions_out_stream.tellp();
|
|
||||||
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
|
|
||||||
|
|
||||||
for (const auto &restriction_container : restrictions_list)
|
|
||||||
{
|
|
||||||
if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
|
|
||||||
SPECIAL_NODEID != restriction_container.restriction.to.node)
|
|
||||||
{
|
|
||||||
restrictions_out_stream.write((char *)&(restriction_container.restriction),
|
|
||||||
sizeof(TurnRestriction));
|
|
||||||
++written_restriction_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
restrictions_out_stream.seekp(count_position);
|
|
||||||
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
|
|
||||||
|
|
||||||
restrictions_out_stream.close();
|
|
||||||
SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
|
|
||||||
|
|
||||||
std::ofstream file_out_stream;
|
std::ofstream file_out_stream;
|
||||||
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
|
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
|
||||||
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
||||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
|
||||||
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
|
||||||
TIMER_START(write_nodes);
|
|
||||||
// identify all used nodes by a merging step of two sorted lists
|
|
||||||
auto node_iterator = all_nodes_list.begin();
|
|
||||||
auto node_id_iterator = used_node_id_list.begin();
|
|
||||||
while (node_id_iterator != used_node_id_list.end() && node_iterator != all_nodes_list.end())
|
|
||||||
{
|
|
||||||
if (*node_id_iterator < node_iterator->node_id)
|
|
||||||
{
|
|
||||||
++node_id_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*node_id_iterator > node_iterator->node_id)
|
|
||||||
{
|
|
||||||
++node_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
|
|
||||||
|
|
||||||
file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
|
PrepareNodes();
|
||||||
|
WriteNodes(file_out_stream);
|
||||||
|
PrepareEdges();
|
||||||
|
WriteEdges(file_out_stream);
|
||||||
|
|
||||||
++number_of_used_nodes;
|
|
||||||
++node_id_iterator;
|
|
||||||
++node_iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_STOP(write_nodes);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] setting number of nodes ... " << std::flush;
|
|
||||||
std::ios::pos_type previous_file_position = file_out_stream.tellp();
|
|
||||||
file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
|
|
||||||
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
|
||||||
file_out_stream.seekp(previous_file_position);
|
|
||||||
|
|
||||||
std::cout << "ok" << std::endl;
|
|
||||||
|
|
||||||
// Sort edges by start.
|
|
||||||
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
|
||||||
TIMER_START(sort_edges_by_start);
|
|
||||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
|
|
||||||
TIMER_STOP(sort_edges_by_start);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
|
||||||
TIMER_START(set_start_coords);
|
|
||||||
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
|
||||||
// Traverse list of edges and nodes in parallel and set start coord
|
|
||||||
node_iterator = all_nodes_list.begin();
|
|
||||||
auto edge_iterator = all_edges_list.begin();
|
|
||||||
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
|
||||||
{
|
|
||||||
if (edge_iterator->start < node_iterator->node_id)
|
|
||||||
{
|
|
||||||
++edge_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (edge_iterator->start > node_iterator->node_id)
|
|
||||||
{
|
|
||||||
node_iterator++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(edge_iterator->start == node_iterator->node_id);
|
|
||||||
edge_iterator->source_coordinate.lat = node_iterator->lat;
|
|
||||||
edge_iterator->source_coordinate.lon = node_iterator->lon;
|
|
||||||
++edge_iterator;
|
|
||||||
}
|
|
||||||
TIMER_STOP(set_start_coords);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
|
|
||||||
|
|
||||||
// Sort Edges by target
|
|
||||||
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
|
||||||
TIMER_START(sort_edges_by_target);
|
|
||||||
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(),
|
|
||||||
stxxl_memory);
|
|
||||||
TIMER_STOP(sort_edges_by_target);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] Setting target coords ... " << std::flush;
|
|
||||||
TIMER_START(set_target_coords);
|
|
||||||
// Traverse list of edges and nodes in parallel and set target coord
|
|
||||||
node_iterator = all_nodes_list.begin();
|
|
||||||
edge_iterator = all_edges_list.begin();
|
|
||||||
|
|
||||||
// Also serializes the edges
|
|
||||||
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
|
||||||
{
|
|
||||||
if (edge_iterator->target < node_iterator->node_id)
|
|
||||||
{
|
|
||||||
++edge_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (edge_iterator->target > node_iterator->node_id)
|
|
||||||
{
|
|
||||||
++node_iterator;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BOOST_ASSERT(edge_iterator->target == node_iterator->node_id);
|
|
||||||
if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
|
|
||||||
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(edge_iterator->speed != -1);
|
|
||||||
edge_iterator->target_coordinate.lat = node_iterator->lat;
|
|
||||||
edge_iterator->target_coordinate.lon = node_iterator->lon;
|
|
||||||
|
|
||||||
const double distance = coordinate_calculation::euclidean_distance(
|
|
||||||
edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
|
|
||||||
node_iterator->lat, node_iterator->lon);
|
|
||||||
|
|
||||||
const double weight = (distance * 10.) / (edge_iterator->speed / 3.6);
|
|
||||||
int integer_weight = std::max(
|
|
||||||
1, (int)std::floor(
|
|
||||||
(edge_iterator->is_duration_set ? edge_iterator->speed : weight) + .5));
|
|
||||||
// FIXME: This means we have a _minimum_ edge length of 1m
|
|
||||||
// maybe use dm as base unit?
|
|
||||||
const int integer_distance = std::max(1, (int)distance);
|
|
||||||
const short zero = 0;
|
|
||||||
const short one = 1;
|
|
||||||
const bool yes = true;
|
|
||||||
const bool no = false;
|
|
||||||
|
|
||||||
file_out_stream.write((char *)&edge_iterator->start, sizeof(unsigned));
|
|
||||||
file_out_stream.write((char *)&edge_iterator->target, sizeof(unsigned));
|
|
||||||
file_out_stream.write((char *)&integer_distance, sizeof(int));
|
|
||||||
switch (edge_iterator->direction)
|
|
||||||
{
|
|
||||||
case ExtractionWay::notSure:
|
|
||||||
file_out_stream.write((char *)&zero, sizeof(short));
|
|
||||||
break;
|
|
||||||
case ExtractionWay::oneway:
|
|
||||||
file_out_stream.write((char *)&one, sizeof(short));
|
|
||||||
break;
|
|
||||||
case ExtractionWay::bidirectional:
|
|
||||||
file_out_stream.write((char *)&zero, sizeof(short));
|
|
||||||
break;
|
|
||||||
case ExtractionWay::opposite:
|
|
||||||
file_out_stream.write((char *)&one, sizeof(short));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw osrm::exception("edge has broken direction");
|
|
||||||
}
|
|
||||||
|
|
||||||
file_out_stream.write((char *)&integer_weight, sizeof(int));
|
|
||||||
file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
|
|
||||||
if (edge_iterator->is_roundabout)
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&yes, sizeof(bool));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&no, sizeof(bool));
|
|
||||||
}
|
|
||||||
if (edge_iterator->is_in_tiny_cc)
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&yes, sizeof(bool));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&no, sizeof(bool));
|
|
||||||
}
|
|
||||||
if (edge_iterator->is_access_restricted)
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&yes, sizeof(bool));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&no, sizeof(bool));
|
|
||||||
}
|
|
||||||
|
|
||||||
// cannot take adress of bit field, so use local
|
|
||||||
const TravelMode travel_mode = edge_iterator->travel_mode;
|
|
||||||
file_out_stream.write((char *)&travel_mode, sizeof(TravelMode));
|
|
||||||
|
|
||||||
if (edge_iterator->is_split)
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&yes, sizeof(bool));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_out_stream.write((char *)&no, sizeof(bool));
|
|
||||||
}
|
|
||||||
++number_of_used_edges;
|
|
||||||
}
|
|
||||||
++edge_iterator;
|
|
||||||
}
|
|
||||||
TIMER_STOP(set_target_coords);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(set_target_coords) << "s" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] setting number of edges ... " << std::flush;
|
|
||||||
|
|
||||||
file_out_stream.seekp(previous_file_position);
|
|
||||||
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
|
||||||
file_out_stream.close();
|
file_out_stream.close();
|
||||||
std::cout << "ok" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "[extractor] writing street name index ... " << std::flush;
|
WriteNames(name_file_name);
|
||||||
TIMER_START(write_name_index);
|
|
||||||
std::string name_file_streamName = (output_file_name + ".names");
|
|
||||||
boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
|
|
||||||
|
|
||||||
unsigned total_length = 0;
|
|
||||||
std::vector<unsigned> name_lengths;
|
|
||||||
for (const std::string &temp_string : name_list)
|
|
||||||
{
|
|
||||||
const unsigned string_length =
|
|
||||||
std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
|
||||||
name_lengths.push_back(string_length);
|
|
||||||
total_length += string_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
RangeTable<> table(name_lengths);
|
|
||||||
name_file_stream << table;
|
|
||||||
|
|
||||||
name_file_stream.write((char *)&total_length, sizeof(unsigned));
|
|
||||||
// write all chars consecutively
|
|
||||||
for (const std::string &temp_string : name_list)
|
|
||||||
{
|
|
||||||
const unsigned string_length =
|
|
||||||
std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
|
||||||
name_file_stream.write(temp_string.c_str(), string_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
name_file_stream.close();
|
|
||||||
TIMER_STOP(write_name_index);
|
|
||||||
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
|
|
||||||
|
|
||||||
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
|
|
||||||
<< number_of_used_edges << " edges";
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
std::cerr << "Caught Execption:" << e.what() << std::endl;
|
std::cerr << "Caught Execption:" << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::WriteNames(const std::string& names_file_name) const
|
||||||
|
{
|
||||||
|
std::cout << "[extractor] writing street name index ... " << std::flush;
|
||||||
|
TIMER_START(write_name_index);
|
||||||
|
boost::filesystem::ofstream name_file_stream(names_file_name, std::ios::binary);
|
||||||
|
|
||||||
|
unsigned total_length = 0;
|
||||||
|
std::vector<unsigned> name_lengths;
|
||||||
|
for (const std::string &temp_string : name_list)
|
||||||
|
{
|
||||||
|
const unsigned string_length =
|
||||||
|
std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||||
|
name_lengths.push_back(string_length);
|
||||||
|
total_length += string_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// builds and writes the index
|
||||||
|
RangeTable<> name_index_range(name_lengths);
|
||||||
|
name_file_stream << name_index_range;
|
||||||
|
|
||||||
|
name_file_stream.write((char *)&total_length, sizeof(unsigned));
|
||||||
|
// write all chars consecutively
|
||||||
|
for (const std::string &temp_string : name_list)
|
||||||
|
{
|
||||||
|
const unsigned string_length =
|
||||||
|
std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||||
|
name_file_stream.write(temp_string.c_str(), string_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
name_file_stream.close();
|
||||||
|
TIMER_STOP(write_name_index);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::PrepareNodes()
|
||||||
|
{
|
||||||
|
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
|
||||||
|
TIMER_START(sorting_used_nodes);
|
||||||
|
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
|
||||||
|
TIMER_STOP(sorting_used_nodes);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sorting_used_nodes) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Erasing duplicate nodes ... " << std::flush;
|
||||||
|
TIMER_START(erasing_dups);
|
||||||
|
auto new_end = std::unique(used_node_id_list.begin(), used_node_id_list.end());
|
||||||
|
used_node_id_list.resize(new_end - used_node_id_list.begin());
|
||||||
|
TIMER_STOP(erasing_dups);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
|
||||||
|
TIMER_START(sorting_nodes);
|
||||||
|
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
|
||||||
|
stxxl_memory);
|
||||||
|
TIMER_STOP(sorting_nodes);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::PrepareEdges()
|
||||||
|
{
|
||||||
|
// Sort edges by start.
|
||||||
|
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
|
||||||
|
TIMER_START(sort_edges_by_start);
|
||||||
|
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
|
||||||
|
TIMER_STOP(sort_edges_by_start);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Setting start coords ... " << std::flush;
|
||||||
|
TIMER_START(set_start_coords);
|
||||||
|
// Traverse list of edges and nodes in parallel and set start coord
|
||||||
|
auto node_iterator = all_nodes_list.begin();
|
||||||
|
auto edge_iterator = all_edges_list.begin();
|
||||||
|
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
||||||
|
{
|
||||||
|
if (edge_iterator->result.source < node_iterator->node_id)
|
||||||
|
{
|
||||||
|
++edge_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (edge_iterator->result.source > node_iterator->node_id)
|
||||||
|
{
|
||||||
|
node_iterator++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(edge_iterator->result.source == node_iterator->node_id);
|
||||||
|
edge_iterator->source_coordinate.lat = node_iterator->lat;
|
||||||
|
edge_iterator->source_coordinate.lon = node_iterator->lon;
|
||||||
|
++edge_iterator;
|
||||||
|
}
|
||||||
|
TIMER_STOP(set_start_coords);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
|
||||||
|
|
||||||
|
// Sort Edges by target
|
||||||
|
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
|
||||||
|
TIMER_START(sort_edges_by_target);
|
||||||
|
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(),
|
||||||
|
stxxl_memory);
|
||||||
|
TIMER_STOP(sort_edges_by_target);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
|
||||||
|
|
||||||
|
// Compute edge weights
|
||||||
|
std::cout << "[extractor] Computing edge weights ... " << std::flush;
|
||||||
|
TIMER_START(compute_weights);
|
||||||
|
node_iterator = all_nodes_list.begin();
|
||||||
|
edge_iterator = all_edges_list.begin();
|
||||||
|
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
|
||||||
|
{
|
||||||
|
if (edge_iterator->result.target < node_iterator->node_id)
|
||||||
|
{
|
||||||
|
// FIXME we are skipping edges here: That means the data is broken!
|
||||||
|
++edge_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (edge_iterator->result.target > node_iterator->node_id)
|
||||||
|
{
|
||||||
|
++node_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(edge_iterator->result.target == node_iterator->node_id);
|
||||||
|
if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
|
||||||
|
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(edge_iterator->weight_data.speed != -1);
|
||||||
|
|
||||||
|
const double distance = coordinate_calculation::euclidean_distance(
|
||||||
|
edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
|
||||||
|
node_iterator->lat, node_iterator->lon);
|
||||||
|
|
||||||
|
const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
|
||||||
|
switch (data.type)
|
||||||
|
{
|
||||||
|
case InternalExtractorEdge::WeightType::EDGE_DURATION:
|
||||||
|
case InternalExtractorEdge::WeightType::WAY_DURATION:
|
||||||
|
return data.duration * 10.;
|
||||||
|
break;
|
||||||
|
case InternalExtractorEdge::WeightType::SPEED:
|
||||||
|
return (distance * 10.) / (data.speed / 3.6);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
osrm::exception("invalid weight type");
|
||||||
|
}
|
||||||
|
return -1.0;
|
||||||
|
}(edge_iterator->weight_data);
|
||||||
|
|
||||||
|
edge_iterator->result.weight = std::max(1, (int)std::floor(weight + .5));
|
||||||
|
}
|
||||||
|
++edge_iterator;
|
||||||
|
}
|
||||||
|
TIMER_STOP(compute_weights);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(compute_weights) << "s" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
|
||||||
|
{
|
||||||
|
std::cout << "[extractor] Writing used egdes ... " << std::flush;
|
||||||
|
TIMER_START(write_edges);
|
||||||
|
// Traverse list of edges and nodes in parallel and set target coord
|
||||||
|
unsigned number_of_used_edges = 0;
|
||||||
|
|
||||||
|
auto start_position = file_out_stream.tellp();
|
||||||
|
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
||||||
|
|
||||||
|
for (const auto& edge : all_edges_list)
|
||||||
|
{
|
||||||
|
if (edge.result.weight > 0)
|
||||||
|
{
|
||||||
|
file_out_stream.write((char*) &edge.result, sizeof(NodeBasedEdge));
|
||||||
|
number_of_used_edges++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TIMER_STOP(write_edges);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] setting number of edges ... " << std::flush;
|
||||||
|
file_out_stream.seekp(start_position);
|
||||||
|
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
|
||||||
|
std::cout << "ok" << std::endl;
|
||||||
|
|
||||||
|
SimpleLogger().Write() << "Processed " << number_of_used_edges << " nodes";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
|
||||||
|
{
|
||||||
|
unsigned number_of_used_nodes = 0;
|
||||||
|
// write dummy value, will be overwritten later
|
||||||
|
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||||
|
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
|
||||||
|
TIMER_START(write_nodes);
|
||||||
|
// identify all used nodes by a merging step of two sorted lists
|
||||||
|
auto node_iterator = all_nodes_list.begin();
|
||||||
|
auto node_id_iterator = used_node_id_list.begin();
|
||||||
|
while (node_id_iterator != used_node_id_list.end() && node_iterator != all_nodes_list.end())
|
||||||
|
{
|
||||||
|
if (*node_id_iterator < node_iterator->node_id)
|
||||||
|
{
|
||||||
|
++node_id_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*node_id_iterator > node_iterator->node_id)
|
||||||
|
{
|
||||||
|
++node_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(*node_id_iterator == node_iterator->node_id);
|
||||||
|
|
||||||
|
file_out_stream.write((char *)&(*node_iterator), sizeof(ExternalMemoryNode));
|
||||||
|
|
||||||
|
++number_of_used_nodes;
|
||||||
|
++node_id_iterator;
|
||||||
|
++node_iterator;
|
||||||
|
}
|
||||||
|
TIMER_STOP(write_nodes);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] setting number of nodes ... " << std::flush;
|
||||||
|
std::ios::pos_type previous_file_position = file_out_stream.tellp();
|
||||||
|
file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
|
||||||
|
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
|
||||||
|
file_out_stream.seekp(previous_file_position);
|
||||||
|
std::cout << "ok" << std::endl;
|
||||||
|
|
||||||
|
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::WriteRestrictions(const std::string& path) const
|
||||||
|
{
|
||||||
|
// serialize restrictions
|
||||||
|
std::ofstream restrictions_out_stream;
|
||||||
|
unsigned written_restriction_count = 0;
|
||||||
|
restrictions_out_stream.open(path.c_str(), std::ios::binary);
|
||||||
|
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
|
||||||
|
const auto count_position = restrictions_out_stream.tellp();
|
||||||
|
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
|
||||||
|
|
||||||
|
for (const auto &restriction_container : restrictions_list)
|
||||||
|
{
|
||||||
|
if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
|
||||||
|
SPECIAL_NODEID != restriction_container.restriction.to.node)
|
||||||
|
{
|
||||||
|
restrictions_out_stream.write((char *)&(restriction_container.restriction),
|
||||||
|
sizeof(TurnRestriction));
|
||||||
|
++written_restriction_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
restrictions_out_stream.seekp(count_position);
|
||||||
|
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
|
||||||
|
restrictions_out_stream.close();
|
||||||
|
SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionContainers::PrepareRestrictions()
|
||||||
|
{
|
||||||
|
std::cout << "[extractor] Sorting used ways ... " << std::flush;
|
||||||
|
TIMER_START(sort_ways);
|
||||||
|
stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
|
||||||
|
FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
|
||||||
|
TIMER_STOP(sort_ways);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Sorting " << restrictions_list.size()
|
||||||
|
<< " restrictions. by from... " << std::flush;
|
||||||
|
TIMER_START(sort_restrictions);
|
||||||
|
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
|
||||||
|
CmpRestrictionContainerByFrom(), stxxl_memory);
|
||||||
|
TIMER_STOP(sort_restrictions);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
|
||||||
|
TIMER_START(fix_restriction_starts);
|
||||||
|
auto restrictions_iterator = restrictions_list.begin();
|
||||||
|
auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
|
||||||
|
|
||||||
|
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
|
||||||
|
restrictions_iterator != restrictions_list.end())
|
||||||
|
{
|
||||||
|
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
|
||||||
|
{
|
||||||
|
++way_start_and_end_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
|
||||||
|
{
|
||||||
|
++restrictions_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
|
||||||
|
restrictions_iterator->restriction.from.way);
|
||||||
|
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
|
||||||
|
|
||||||
|
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
|
||||||
|
{
|
||||||
|
restrictions_iterator->restriction.from.node =
|
||||||
|
way_start_and_end_iterator->first_segment_target_id;
|
||||||
|
}
|
||||||
|
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
|
||||||
|
{
|
||||||
|
restrictions_iterator->restriction.from.node =
|
||||||
|
way_start_and_end_iterator->last_segment_source_id;
|
||||||
|
}
|
||||||
|
++restrictions_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMER_STOP(fix_restriction_starts);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
|
||||||
|
TIMER_START(sort_restrictions_to);
|
||||||
|
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
|
||||||
|
CmpRestrictionContainerByTo(), stxxl_memory);
|
||||||
|
TIMER_STOP(sort_restrictions_to);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
|
||||||
|
TIMER_START(fix_restriction_ends);
|
||||||
|
restrictions_iterator = restrictions_list.begin();
|
||||||
|
way_start_and_end_iterator = way_start_end_id_list.cbegin();
|
||||||
|
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
|
||||||
|
restrictions_iterator != restrictions_list.end())
|
||||||
|
{
|
||||||
|
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
|
||||||
|
{
|
||||||
|
++way_start_and_end_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
|
||||||
|
{
|
||||||
|
++restrictions_iterator;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
|
||||||
|
restrictions_iterator->restriction.to.way);
|
||||||
|
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
|
||||||
|
|
||||||
|
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
|
||||||
|
{
|
||||||
|
restrictions_iterator->restriction.to.node =
|
||||||
|
way_start_and_end_iterator->first_segment_target_id;
|
||||||
|
}
|
||||||
|
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
|
||||||
|
{
|
||||||
|
restrictions_iterator->restriction.to.node =
|
||||||
|
way_start_and_end_iterator->last_segment_source_id;
|
||||||
|
}
|
||||||
|
++restrictions_iterator;
|
||||||
|
}
|
||||||
|
TIMER_STOP(fix_restriction_ends);
|
||||||
|
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
|
||||||
|
}
|
||||||
|
@ -39,6 +39,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
/**
|
/**
|
||||||
* Uses external memory containers from stxxl to store all the data that
|
* Uses external memory containers from stxxl to store all the data that
|
||||||
* is collected by the extractor callbacks.
|
* is collected by the extractor callbacks.
|
||||||
|
*
|
||||||
|
* The data is the filtered, aggregated and finally written to disk.
|
||||||
*/
|
*/
|
||||||
class ExtractionContainers
|
class ExtractionContainers
|
||||||
{
|
{
|
||||||
@ -49,6 +51,14 @@ class ExtractionContainers
|
|||||||
#else
|
#else
|
||||||
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
|
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
|
||||||
#endif
|
#endif
|
||||||
|
void PrepareNodes();
|
||||||
|
void PrepareRestrictions();
|
||||||
|
void PrepareEdges();
|
||||||
|
|
||||||
|
void WriteNodes(std::ofstream& file_out_stream) const;
|
||||||
|
void WriteRestrictions(const std::string& restrictions_file_name) const;
|
||||||
|
void WriteEdges(std::ofstream& file_out_stream) const;
|
||||||
|
void WriteNames(const std::string& names_file_name) const;
|
||||||
public:
|
public:
|
||||||
using STXXLNodeIDVector = stxxl::vector<NodeID>;
|
using STXXLNodeIDVector = stxxl::vector<NodeID>;
|
||||||
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
|
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
|
||||||
@ -70,7 +80,8 @@ class ExtractionContainers
|
|||||||
~ExtractionContainers();
|
~ExtractionContainers();
|
||||||
|
|
||||||
void PrepareData(const std::string &output_file_name,
|
void PrepareData(const std::string &output_file_name,
|
||||||
const std::string &restrictions_file_name);
|
const std::string &restrictions_file_name,
|
||||||
|
const std::string &names_file_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* EXTRACTION_CONTAINERS_HPP */
|
#endif /* EXTRACTION_CONTAINERS_HPP */
|
||||||
|
@ -102,7 +102,7 @@ unsigned parseDuration(const std::string &s)
|
|||||||
minutes = cast::string_to_int(result[1]);
|
minutes = cast::string_to_int(result[1]);
|
||||||
hours = cast::string_to_int(result[0]);
|
hours = cast::string_to_int(result[0]);
|
||||||
}
|
}
|
||||||
return 10 * (3600 * hours + 60 * minutes + seconds);
|
return (3600 * hours + 60 * minutes + seconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (iso_8601_duration_is_valid(s))
|
else if (iso_8601_duration_is_valid(s))
|
||||||
|
@ -237,7 +237,8 @@ int extractor::run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
extraction_containers.PrepareData(config.output_file_name,
|
extraction_containers.PrepareData(config.output_file_name,
|
||||||
config.restriction_file_name);
|
config.restriction_file_name,
|
||||||
|
config.names_file_name);
|
||||||
TIMER_STOP(extracting);
|
TIMER_STOP(extracting);
|
||||||
SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
|
||||||
SimpleLogger().Write() << "To prepare the data for routing, run: "
|
SimpleLogger().Write() << "To prepare the data for routing, run: "
|
||||||
|
@ -108,17 +108,40 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
<< " of size " << input_way.nodes().size();
|
<< " of size " << input_way.nodes().size();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InternalExtractorEdge::WeightData forward_weight_data;
|
||||||
|
InternalExtractorEdge::WeightData backward_weight_data;
|
||||||
|
|
||||||
if (0 < parsed_way.duration)
|
if (0 < parsed_way.duration)
|
||||||
{
|
{
|
||||||
// TODO: iterate all way segments and set duration corresponding to the length of each
|
const unsigned num_edges = (input_way.nodes().size() - 1);
|
||||||
// segment
|
// FIXME We devide by the numer of nodes here, but should rather consider
|
||||||
const_cast<ExtractionWay &>(parsed_way).forward_speed =
|
// the length of each segment. We would eigther have to compute the length
|
||||||
parsed_way.duration / (input_way.nodes().size() - 1);
|
// of the whole way here (we can't: no node coordinates) or push that back
|
||||||
const_cast<ExtractionWay &>(parsed_way).backward_speed =
|
// to the container and keep a reference to the way.
|
||||||
parsed_way.duration / (input_way.nodes().size() - 1);
|
forward_weight_data.duration = parsed_way.duration / num_edges;
|
||||||
|
forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
|
||||||
|
backward_weight_data.duration = parsed_way.duration / num_edges;
|
||||||
|
backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (parsed_way.forward_speed > 0 &&
|
||||||
|
parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||||
|
{
|
||||||
|
forward_weight_data.speed = parsed_way.forward_speed;
|
||||||
|
forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
|
||||||
|
}
|
||||||
|
if (parsed_way.backward_speed > 0 &&
|
||||||
|
parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
|
||||||
|
{
|
||||||
|
backward_weight_data.speed = parsed_way.backward_speed;
|
||||||
|
backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
|
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID
|
||||||
|
&& backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
|
||||||
{
|
{
|
||||||
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
|
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
|
||||||
return;
|
return;
|
||||||
@ -144,36 +167,34 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
((parsed_way.forward_speed != parsed_way.backward_speed) ||
|
((parsed_way.forward_speed != parsed_way.backward_speed) ||
|
||||||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
|
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
|
||||||
|
|
||||||
auto pair_wise_segment_split =
|
// lambda to add edge to container
|
||||||
|
auto pair_wise_segment_split_forward =
|
||||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
|
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
|
||||||
{
|
{
|
||||||
// SimpleLogger().Write() << "adding edge (" << first_node.ref() << "," <<
|
const bool forward_only = split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
|
||||||
// last_node.ref() << "), fwd speed: " << parsed_way.forward_speed;
|
|
||||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||||
first_node.ref(), last_node.ref(),
|
first_node.ref(), last_node.ref(), name_id, forward_weight_data,
|
||||||
((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)
|
true, !forward_only, parsed_way.roundabout, parsed_way.ignore_in_grid,
|
||||||
? ExtractionWay::oneway
|
parsed_way.is_access_restricted, parsed_way.forward_travel_mode, split_edge));
|
||||||
: ExtractionWay::bidirectional),
|
|
||||||
parsed_way.forward_speed, name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
|
|
||||||
(0 < parsed_way.duration), parsed_way.is_access_restricted,
|
|
||||||
parsed_way.forward_travel_mode, split_edge));
|
|
||||||
external_memory.used_node_id_list.push_back(first_node.ref());
|
external_memory.used_node_id_list.push_back(first_node.ref());
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
|
const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
|
||||||
|
// traverse way in reverse in this case
|
||||||
if (is_opposite_way)
|
if (is_opposite_way)
|
||||||
{
|
{
|
||||||
|
// why don't we have to swap the parsed_way.forward/backward speed here as well
|
||||||
const_cast<ExtractionWay &>(parsed_way).forward_travel_mode =
|
const_cast<ExtractionWay &>(parsed_way).forward_travel_mode =
|
||||||
parsed_way.backward_travel_mode;
|
parsed_way.backward_travel_mode;
|
||||||
const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||||
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
|
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
|
||||||
pair_wise_segment_split);
|
pair_wise_segment_split_forward);
|
||||||
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
|
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
|
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
|
||||||
pair_wise_segment_split);
|
pair_wise_segment_split_forward);
|
||||||
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
|
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,22 +208,19 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
|
|
||||||
if (split_edge)
|
if (split_edge)
|
||||||
{ // Only true if the way should be split
|
{ // Only true if the way should be split
|
||||||
BOOST_ASSERT(parsed_way.backward_travel_mode > 0);
|
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
|
||||||
auto pair_wise_segment_split_2 =
|
auto pair_wise_segment_split_2 =
|
||||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
|
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
|
||||||
{
|
{
|
||||||
// SimpleLogger().Write() << "adding edge (" << last_node.ref() << "," <<
|
|
||||||
// first_node.ref() << "), bwd speed: " << parsed_way.backward_speed;
|
|
||||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||||
last_node.ref(), first_node.ref(), ExtractionWay::oneway, parsed_way.backward_speed,
|
last_node.ref(), first_node.ref(), name_id, backward_weight_data,
|
||||||
name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
|
true, false, parsed_way.roundabout, parsed_way.ignore_in_grid,
|
||||||
(0 < parsed_way.duration), parsed_way.is_access_restricted,
|
parsed_way.is_access_restricted, parsed_way.backward_travel_mode, split_edge));
|
||||||
parsed_way.backward_travel_mode, split_edge));
|
external_memory.used_node_id_list.push_back(last_node.ref());
|
||||||
};
|
};
|
||||||
|
|
||||||
if (is_opposite_way)
|
if (is_opposite_way)
|
||||||
{
|
{
|
||||||
// SimpleLogger().Write() << "opposite2";
|
|
||||||
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
|
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
|
||||||
pair_wise_segment_split_2);
|
pair_wise_segment_split_2);
|
||||||
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
|
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
|
||||||
@ -211,7 +229,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
|||||||
{
|
{
|
||||||
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
|
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
|
||||||
pair_wise_segment_split_2);
|
pair_wise_segment_split_2);
|
||||||
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
|
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
external_memory.way_start_end_id_list.push_back(
|
external_memory.way_start_end_id_list.push_back(
|
||||||
|
@ -135,6 +135,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
|||||||
boost::filesystem::path &input_path = extractor_config.input_path;
|
boost::filesystem::path &input_path = extractor_config.input_path;
|
||||||
extractor_config.output_file_name = input_path.string();
|
extractor_config.output_file_name = input_path.string();
|
||||||
extractor_config.restriction_file_name = input_path.string();
|
extractor_config.restriction_file_name = input_path.string();
|
||||||
|
extractor_config.names_file_name = input_path.string();
|
||||||
extractor_config.timestamp_file_name = input_path.string();
|
extractor_config.timestamp_file_name = input_path.string();
|
||||||
std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
|
std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
|
||||||
if (pos == std::string::npos)
|
if (pos == std::string::npos)
|
||||||
@ -156,12 +157,14 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
|||||||
{
|
{
|
||||||
extractor_config.output_file_name.append(".osrm");
|
extractor_config.output_file_name.append(".osrm");
|
||||||
extractor_config.restriction_file_name.append(".osrm.restrictions");
|
extractor_config.restriction_file_name.append(".osrm.restrictions");
|
||||||
|
extractor_config.names_file_name.append(".osrm.names");
|
||||||
extractor_config.timestamp_file_name.append(".osrm.timestamp");
|
extractor_config.timestamp_file_name.append(".osrm.timestamp");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
extractor_config.output_file_name.replace(pos, 5, ".osrm");
|
extractor_config.output_file_name.replace(pos, 5, ".osrm");
|
||||||
extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
|
extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
|
||||||
|
extractor_config.names_file_name.replace(pos, 5, ".osrm.names");
|
||||||
extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
|
extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,6 +172,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
|
|||||||
{
|
{
|
||||||
extractor_config.output_file_name.replace(pos, 8, ".osrm");
|
extractor_config.output_file_name.replace(pos, 8, ".osrm");
|
||||||
extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
|
extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
|
||||||
|
extractor_config.names_file_name.replace(pos, 8, ".osrm.names");
|
||||||
extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
|
extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ struct ExtractorConfig
|
|||||||
|
|
||||||
std::string output_file_name;
|
std::string output_file_name;
|
||||||
std::string restriction_file_name;
|
std::string restriction_file_name;
|
||||||
|
std::string names_file_name;
|
||||||
std::string timestamp_file_name;
|
std::string timestamp_file_name;
|
||||||
|
|
||||||
unsigned requested_num_threads;
|
unsigned requested_num_threads;
|
||||||
|
@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
#include "../data_structures/travel_mode.hpp"
|
#include "../data_structures/travel_mode.hpp"
|
||||||
|
#include "../data_structures/import_edge.hpp"
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
@ -37,83 +38,94 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
struct InternalExtractorEdge
|
struct InternalExtractorEdge
|
||||||
{
|
{
|
||||||
InternalExtractorEdge()
|
// specify the type of the weight data
|
||||||
: start(0), target(0), speed(0), name_id(0), direction(0), is_roundabout(false),
|
enum class WeightType : char {
|
||||||
is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
|
INVALID,
|
||||||
is_split(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
SPEED,
|
||||||
|
EDGE_DURATION,
|
||||||
|
WAY_DURATION,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WeightData
|
||||||
|
{
|
||||||
|
|
||||||
|
WeightData() : duration(0.0), type(WeightType::INVALID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
double duration;
|
||||||
|
double speed;
|
||||||
|
};
|
||||||
|
WeightType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit InternalExtractorEdge()
|
||||||
|
: result(0, 0, 0, 0, false, false, false, false, false,
|
||||||
|
TRAVEL_MODE_INACCESSIBLE, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit InternalExtractorEdge(NodeID start,
|
explicit InternalExtractorEdge(NodeID source,
|
||||||
NodeID target,
|
NodeID target,
|
||||||
short direction,
|
NodeID name_id,
|
||||||
double speed,
|
const WeightData& weight_data,
|
||||||
unsigned name_id,
|
bool forward,
|
||||||
bool is_roundabout,
|
bool backward,
|
||||||
bool is_in_tiny_cc,
|
bool roundabout,
|
||||||
bool is_duration_set,
|
bool in_tiny_cc,
|
||||||
bool is_access_restricted,
|
bool access_restricted,
|
||||||
TravelMode travel_mode,
|
TravelMode travel_mode,
|
||||||
bool is_split)
|
bool is_split)
|
||||||
: start(start), target(target), speed(speed), name_id(name_id), direction(direction),
|
: result(source, target, name_id, 0, forward, backward, roundabout,
|
||||||
is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
|
in_tiny_cc, access_restricted, travel_mode, is_split),
|
||||||
is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
|
weight_data(weight_data)
|
||||||
is_split(is_split), travel_mode(travel_mode)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data that will be written to disk
|
||||||
|
NodeBasedEdge result;
|
||||||
|
// intermediate edge weight
|
||||||
|
WeightData weight_data;
|
||||||
|
// coordinate of the source node
|
||||||
|
FixedPointCoordinate source_coordinate;
|
||||||
|
|
||||||
|
|
||||||
// necessary static util functions for stxxl's sorting
|
// necessary static util functions for stxxl's sorting
|
||||||
static InternalExtractorEdge min_value()
|
static InternalExtractorEdge min_value()
|
||||||
{
|
{
|
||||||
return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false,
|
return InternalExtractorEdge(0, 0, 0, WeightData(), false, false, false,
|
||||||
TRAVEL_MODE_INACCESSIBLE, false);
|
false, false, TRAVEL_MODE_INACCESSIBLE, false);
|
||||||
}
|
}
|
||||||
static InternalExtractorEdge max_value()
|
static InternalExtractorEdge max_value()
|
||||||
{
|
{
|
||||||
return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false,
|
return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, WeightData(), false, false,
|
||||||
false, TRAVEL_MODE_INACCESSIBLE, false);
|
false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeID start;
|
|
||||||
NodeID target;
|
|
||||||
double speed;
|
|
||||||
unsigned name_id;
|
|
||||||
short direction;
|
|
||||||
bool is_roundabout : 1;
|
|
||||||
bool is_in_tiny_cc : 1;
|
|
||||||
bool is_duration_set : 1;
|
|
||||||
bool is_access_restricted : 1;
|
|
||||||
bool is_split : 1;
|
|
||||||
TravelMode travel_mode : 4;
|
|
||||||
|
|
||||||
FixedPointCoordinate source_coordinate;
|
|
||||||
FixedPointCoordinate target_coordinate;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CmpEdgeByStartID
|
struct CmpEdgeByStartID
|
||||||
{
|
{
|
||||||
using value_type = InternalExtractorEdge;
|
using value_type = InternalExtractorEdge;
|
||||||
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
|
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
|
||||||
{
|
{
|
||||||
return a.start < b.start;
|
return lhs.result.source < rhs.result.source;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type max_value() { return InternalExtractorEdge::max_value(); }
|
value_type max_value() { return InternalExtractorEdge::max_value(); }
|
||||||
|
|
||||||
value_type min_value() { return InternalExtractorEdge::min_value(); }
|
value_type min_value() { return InternalExtractorEdge::min_value(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CmpEdgeByTargetID
|
struct CmpEdgeByTargetID
|
||||||
{
|
{
|
||||||
using value_type = InternalExtractorEdge;
|
using value_type = InternalExtractorEdge;
|
||||||
|
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
|
||||||
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
|
|
||||||
{
|
{
|
||||||
return a.target < b.target;
|
return lhs.result.target < rhs.result.target;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type max_value() { return InternalExtractorEdge::max_value(); }
|
value_type max_value() { return InternalExtractorEdge::max_value(); }
|
||||||
|
|
||||||
value_type min_value() { return InternalExtractorEdge::min_value(); }
|
value_type min_value() { return InternalExtractorEdge::min_value(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ std::size_t LoadGraph(const char* path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// load graph data
|
// load graph data
|
||||||
std::vector<ImportEdge> edge_list;
|
std::vector<NodeBasedEdge> edge_list;
|
||||||
std::vector<NodeID> traffic_light_node_list;
|
std::vector<NodeID> traffic_light_node_list;
|
||||||
|
|
||||||
auto number_of_nodes = loadNodesFromFile(input_stream, barrier_node_list,
|
auto number_of_nodes = loadNodesFromFile(input_stream, barrier_node_list,
|
||||||
@ -109,7 +109,7 @@ std::size_t LoadGraph(const char* path,
|
|||||||
coordinate_list,
|
coordinate_list,
|
||||||
ext_to_int_id_map);
|
ext_to_int_id_map);
|
||||||
|
|
||||||
auto number_of_edges = loadEdgesFromFile(input_stream, ext_to_int_id_map, edge_list);
|
loadEdgesFromFile(input_stream, ext_to_int_id_map, edge_list);
|
||||||
|
|
||||||
traffic_light_node_list.clear();
|
traffic_light_node_list.clear();
|
||||||
traffic_light_node_list.shrink_to_fit();
|
traffic_light_node_list.shrink_to_fit();
|
||||||
|
@ -41,24 +41,24 @@ BOOST_AUTO_TEST_CASE(all_necessary_test)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(common_durations_get_translated)
|
BOOST_AUTO_TEST_CASE(common_durations_get_translated)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(parseDuration("00:01"), 600);
|
BOOST_CHECK_EQUAL(parseDuration("00:01"), 60);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 610);
|
BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 61);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("01:01"), 36600);
|
BOOST_CHECK_EQUAL(parseDuration("01:01"), 3660);
|
||||||
|
|
||||||
// check all combinations of iso duration tokens
|
// check all combinations of iso duration tokens
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 610);
|
BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 61);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 36010);
|
BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 3601);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT15M"), 9000);
|
BOOST_CHECK_EQUAL(parseDuration("PT15M"), 900);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT15S"), 150);
|
BOOST_CHECK_EQUAL(parseDuration("PT15S"), 15);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT15H"), 540000);
|
BOOST_CHECK_EQUAL(parseDuration("PT15H"), 54000);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 45000);
|
BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 4500);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 45010);
|
BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 4501);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
|
BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT15m"), 9000);
|
BOOST_CHECK_EQUAL(parseDuration("PT15m"), 900);
|
||||||
BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 45000);
|
BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 4500);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -170,83 +170,56 @@ NodeID loadNodesFromFile(std::istream &input_stream,
|
|||||||
* Reads a .osrm file and produces the edges. Edges reference nodes in the old
|
* Reads a .osrm file and produces the edges. Edges reference nodes in the old
|
||||||
* OSM based format, we need to renumber it here.
|
* OSM based format, we need to renumber it here.
|
||||||
*/
|
*/
|
||||||
template <typename EdgeT>
|
|
||||||
NodeID loadEdgesFromFile(std::istream &input_stream,
|
NodeID loadEdgesFromFile(std::istream &input_stream,
|
||||||
const std::unordered_map<NodeID, NodeID> &ext_to_int_id_map,
|
const std::unordered_map<NodeID, NodeID> &ext_to_int_id_map,
|
||||||
std::vector<EdgeT> &edge_list)
|
std::vector<NodeBasedEdge> &edge_list)
|
||||||
{
|
{
|
||||||
EdgeWeight weight;
|
|
||||||
NodeID source, target;
|
|
||||||
unsigned nameID;
|
|
||||||
int length;
|
|
||||||
short dir; // direction (0 = open, 1 = forward, 2+ = open)
|
|
||||||
bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
|
|
||||||
TravelMode travel_mode;
|
|
||||||
|
|
||||||
EdgeID m;
|
EdgeID m;
|
||||||
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
|
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
|
||||||
edge_list.reserve(m);
|
edge_list.reserve(m);
|
||||||
SimpleLogger().Write() << " and " << m << " edges ";
|
SimpleLogger().Write() << " and " << m << " edges ";
|
||||||
|
|
||||||
|
NodeBasedEdge edge(0, 0, 0, 0, false, false, false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
|
||||||
for (EdgeID i = 0; i < m; ++i)
|
for (EdgeID i = 0; i < m; ++i)
|
||||||
{
|
{
|
||||||
input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
|
input_stream.read(reinterpret_cast<char *>(&edge), sizeof(NodeBasedEdge));
|
||||||
input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
|
BOOST_ASSERT_MSG(edge.weight > 0, "loaded null weight");
|
||||||
input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
|
BOOST_ASSERT_MSG(edge.forward || edge.backward, "loaded null weight");
|
||||||
input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
|
BOOST_ASSERT_MSG(edge.travel_mode != TRAVEL_MODE_INACCESSIBLE, "loaded null weight");
|
||||||
input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
|
|
||||||
input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
|
|
||||||
input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
|
|
||||||
input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
|
|
||||||
input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
|
|
||||||
input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
|
|
||||||
input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
|
|
||||||
|
|
||||||
BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
|
|
||||||
BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
|
|
||||||
BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
|
|
||||||
|
|
||||||
bool forward = true;
|
|
||||||
bool backward = true;
|
|
||||||
if (1 == dir)
|
|
||||||
{
|
|
||||||
backward = false;
|
|
||||||
}
|
|
||||||
if (2 == dir)
|
|
||||||
{
|
|
||||||
forward = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// translate the external NodeIDs to internal IDs
|
// translate the external NodeIDs to internal IDs
|
||||||
auto internal_id_iter = ext_to_int_id_map.find(source);
|
auto internal_id_iter = ext_to_int_id_map.find(edge.source);
|
||||||
if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
|
if (ext_to_int_id_map.find(edge.source) == ext_to_int_id_map.end())
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
|
SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << edge.source;
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
source = internal_id_iter->second;
|
edge.source = internal_id_iter->second;
|
||||||
internal_id_iter = ext_to_int_id_map.find(target);
|
internal_id_iter = ext_to_int_id_map.find(edge.target);
|
||||||
if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
|
if (ext_to_int_id_map.find(edge.target) == ext_to_int_id_map.end())
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
|
SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << edge.target;
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
target = internal_id_iter->second;
|
edge.target = internal_id_iter->second;
|
||||||
BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
|
BOOST_ASSERT_MSG(edge.source != SPECIAL_NODEID && edge.target != SPECIAL_NODEID,
|
||||||
"nonexisting source or target");
|
"nonexisting source or target");
|
||||||
|
|
||||||
if (source > target)
|
if (edge.source > edge.target)
|
||||||
{
|
{
|
||||||
std::swap(source, target);
|
std::swap(edge.source, edge.target);
|
||||||
std::swap(forward, backward);
|
|
||||||
|
// std::swap does not work with bit-fields
|
||||||
|
bool temp = edge.forward;
|
||||||
|
edge.forward = edge.backward;
|
||||||
|
edge.backward = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
edge_list.emplace_back(source, target, nameID, weight, forward, backward, is_roundabout,
|
edge_list.push_back(edge);
|
||||||
ignore_in_grid, is_access_restricted, travel_mode, is_split);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tbb::parallel_sort(edge_list.begin(), edge_list.end());
|
tbb::parallel_sort(edge_list.begin(), edge_list.end());
|
||||||
@ -304,7 +277,7 @@ NodeID loadEdgesFromFile(std::istream &input_stream,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto new_end_iter =
|
const auto new_end_iter =
|
||||||
std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
|
std::remove_if(edge_list.begin(), edge_list.end(), [](const NodeBasedEdge &edge)
|
||||||
{
|
{
|
||||||
return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
|
return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
|
||||||
});
|
});
|
||||||
|
@ -90,7 +90,7 @@ template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
|
|||||||
|
|
||||||
unsigned get_duration() const
|
unsigned get_duration() const
|
||||||
{
|
{
|
||||||
unsigned temp = 10 * (3600 * hours + 60 * minutes + seconds);
|
unsigned temp = (3600 * hours + 60 * minutes + seconds);
|
||||||
if (temp == 0)
|
if (temp == 0)
|
||||||
{
|
{
|
||||||
temp = std::numeric_limits<unsigned>::max();
|
temp = std::numeric_limits<unsigned>::max();
|
||||||
|
Loading…
Reference in New Issue
Block a user