osrm-backend/contractor/processing_chain.cpp

582 lines
23 KiB
C++
Raw Normal View History

2014-07-03 07:29:15 -04:00
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
2014-07-03 07:29:15 -04:00
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2014-11-28 04:29:56 -05:00
#include "processing_chain.hpp"
#include "contractor.hpp"
#include "../algorithms/crc32_processor.hpp"
#include "../data_structures/deallocating_vector.hpp"
#include "../data_structures/static_rtree.hpp"
#include "../data_structures/restriction_map.hpp"
2015-01-27 11:44:46 -05:00
#include "../util/git_sha.hpp"
#include "../util/graph_loader.hpp"
#include "../util/integer_range.hpp"
#include "../util/lua_util.hpp"
#include "../util/make_unique.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"
2014-07-03 07:29:15 -04:00
#include "../typedefs.h"
#include <boost/filesystem/fstream.hpp>
#include <boost/program_options.hpp>
2014-07-03 07:29:15 -04:00
#include <tbb/task_scheduler_init.h>
#include <tbb/parallel_sort.h>
#include <chrono>
#include <memory>
#include <string>
#include <thread>
#include <vector>
Prepare::Prepare() : requested_num_threads(1) {}
2014-07-03 07:29:15 -04:00
Prepare::~Prepare() {}
2014-07-03 07:29:15 -04:00
int Prepare::Process(int argc, char *argv[])
{
#ifdef WIN32
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
#else
static_assert(sizeof(ImportEdge) == 20,
"changing ImportEdge type has influence on memory consumption!");
static_assert(sizeof(EdgeBasedEdge) == 16,
"changing EdgeBasedEdge type has influence on memory consumption!");
#endif
2014-07-03 07:29:15 -04:00
LogPolicy::GetInstance().Unmute();
TIMER_START(preparing);
if (!ParseArguments(argc, argv))
{
return 0;
}
if (!boost::filesystem::is_regular_file(osrm_input_path))
2014-07-03 07:29:15 -04:00
{
SimpleLogger().Write(logWARNING) << "Input file " << osrm_input_path.string() << " not found!";
2014-07-03 07:29:15 -04:00
return 1;
}
if (!boost::filesystem::is_regular_file(profile_path))
{
SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!";
2014-07-03 07:29:15 -04:00
return 1;
}
if (1 > requested_num_threads)
{
SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
return 1;
}
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
SimpleLogger().Write() << "Input file: " << osrm_input_path.filename().string();
2014-07-03 07:29:15 -04:00
SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
SimpleLogger().Write() << "Threads: " << requested_num_threads;
if (recommended_num_threads != requested_num_threads)
{
SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
<< recommended_num_threads
<< "! This setting may have performance side-effects.";
}
tbb::task_scheduler_init init(requested_num_threads);
LogPolicy::GetInstance().Unmute();
node_output_path = osrm_input_path.string() + ".nodes";
edge_output_path = osrm_input_path.string() + ".edges";
geometry_output_path = osrm_input_path.string() + ".geometry";
graph_output_path = osrm_input_path.string() + ".hsgr";
rtree_nodes_output_path = osrm_input_path.string() + ".ramIndex";
rtree_leafs_output_path = osrm_input_path.string() + ".fileIndex";
2014-07-03 07:29:15 -04:00
// Create a new lua state
SimpleLogger().Write() << "Generating edge-expanded graph representation";
2014-07-03 07:29:15 -04:00
TIMER_START(expansion);
2014-07-03 07:29:15 -04:00
auto node_based_edge_list = osrm::make_unique<std::vector<EdgeBasedNode>>();;
2014-07-03 07:29:15 -04:00
DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
auto internal_to_external_node_map = osrm::make_unique<std::vector<QueryNode>>();
auto graph_size =
BuildEdgeExpandedGraph(*internal_to_external_node_map,
*node_based_edge_list, edge_based_edge_list);
2014-07-03 07:29:15 -04:00
auto number_of_node_based_nodes = graph_size.first;
auto number_of_edge_based_nodes = graph_size.second;
2014-07-03 07:29:15 -04:00
TIMER_STOP(expansion);
SimpleLogger().Write() << "building r-tree ...";
TIMER_START(rtree);
BuildRTree(*node_based_edge_list, *internal_to_external_node_map);
TIMER_STOP(rtree);
2014-07-03 07:29:15 -04:00
SimpleLogger().Write() << "writing node map ...";
WriteNodeMapping(std::move(internal_to_external_node_map));
2014-07-03 07:29:15 -04:00
// Contracting the edge-expanded graph
2014-07-03 07:29:15 -04:00
TIMER_START(contraction);
2015-04-23 12:53:36 -04:00
auto contracted_edge_list = osrm::make_unique<DeallocatingVector<QueryEdge>>();
ContractGraph(number_of_edge_based_nodes, edge_based_edge_list, *contracted_edge_list);
2014-07-03 07:29:15 -04:00
TIMER_STOP(contraction);
SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
2015-04-23 12:53:36 -04:00
std::size_t number_of_used_edges = WriteContractedGraph(number_of_edge_based_nodes,
std::move(node_based_edge_list),
std::move(contracted_edge_list));
TIMER_STOP(preparing);
SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
<< " nodes/sec and "
<< (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
2014-07-03 07:29:15 -04:00
2015-04-23 12:53:36 -04:00
SimpleLogger().Write() << "Contraction: "
<< (number_of_edge_based_nodes / TIMER_SEC(contraction))
<< " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
<< " edges/sec";
SimpleLogger().Write() << "finished preprocessing";
return 0;
}
std::size_t Prepare::WriteContractedGraph(unsigned number_of_edge_based_nodes,
std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list,
std::unique_ptr<DeallocatingVector<QueryEdge>> contracted_edge_list)
{
const unsigned crc32_value = CalculateEdgeChecksum(std::move(node_based_edge_list));
// Sorting contracted edges in a way that the static query graph can read some in in-place.
tbb::parallel_sort(contracted_edge_list->begin(), contracted_edge_list->end());
const unsigned contracted_edge_count = contracted_edge_list->size();
2014-07-03 07:29:15 -04:00
SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
<< " edges";
2015-04-23 12:53:36 -04:00
FingerPrint fingerprint_orig;
boost::filesystem::ofstream hsgr_output_stream(graph_output_path, std::ios::binary);
2014-07-03 07:29:15 -04:00
hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
2014-08-07 07:40:43 -04:00
const unsigned max_used_node_id = 1 + [&contracted_edge_list]
{
2014-08-07 06:02:57 -04:00
unsigned tmp_max = 0;
2015-04-23 12:53:36 -04:00
for (const QueryEdge &edge : *contracted_edge_list)
2014-08-07 06:02:57 -04:00
{
BOOST_ASSERT(SPECIAL_NODEID != edge.source);
BOOST_ASSERT(SPECIAL_NODEID != edge.target);
tmp_max = std::max(tmp_max, edge.source);
tmp_max = std::max(tmp_max, edge.target);
}
return tmp_max;
}();
2014-07-03 07:29:15 -04:00
SimpleLogger().Write(logDEBUG) << "input graph has " << number_of_edge_based_nodes << " nodes";
2014-07-03 07:29:15 -04:00
SimpleLogger().Write(logDEBUG) << "contracted graph has " << max_used_node_id << " nodes";
std::vector<StaticGraph<EdgeData>::NodeArrayEntry> node_array;
node_array.resize(number_of_edge_based_nodes + 1);
SimpleLogger().Write() << "Building node array";
StaticGraph<EdgeData>::EdgeIterator edge = 0;
StaticGraph<EdgeData>::EdgeIterator position = 0;
StaticGraph<EdgeData>::EdgeIterator last_edge = edge;
// initializing 'first_edge'-field of nodes:
2014-08-05 11:19:09 -04:00
for (const auto node : osrm::irange(0u, max_used_node_id))
2014-07-03 07:29:15 -04:00
{
last_edge = edge;
2015-04-23 12:53:36 -04:00
while ((edge < contracted_edge_count) && ((*contracted_edge_list)[edge].source == node))
2014-07-03 07:29:15 -04:00
{
++edge;
}
node_array[node].first_edge = position; //=edge
position += edge - last_edge; // remove
}
2014-08-05 11:19:09 -04:00
for (const auto sentinel_counter : osrm::irange<unsigned>(max_used_node_id, node_array.size()))
2014-07-03 07:29:15 -04:00
{
// sentinel element, guarded against underflow
node_array[sentinel_counter].first_edge = contracted_edge_count;
}
SimpleLogger().Write() << "Serializing node array";
const unsigned node_array_size = node_array.size();
// serialize crc32, aka checksum
hsgr_output_stream.write((char *)&crc32_value, sizeof(unsigned));
2014-07-03 07:29:15 -04:00
// serialize number of nodes
hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
// serialize number of edges
hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
// serialize all nodes
if (node_array_size > 0)
{
hsgr_output_stream.write((char *)&node_array[0],
sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
2014-07-03 07:29:15 -04:00
}
// serialize all edges
2014-07-03 07:29:15 -04:00
SimpleLogger().Write() << "Building edge array";
edge = 0;
int number_of_used_edges = 0;
StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
2015-04-23 12:53:36 -04:00
for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list->size()))
2014-07-03 07:29:15 -04:00
{
// no eigen loops
2015-04-23 12:53:36 -04:00
BOOST_ASSERT(contracted_edge_list->(edge).source != contracted_edge_list->(edge).target);
current_edge.target = (*contracted_edge_list)[edge].target;
current_edge.data = (*contracted_edge_list)[edge].data;
2014-07-03 07:29:15 -04:00
// every target needs to be valid
BOOST_ASSERT(current_edge.target < max_used_node_id);
#ifndef NDEBUG
if (current_edge.data.distance <= 0)
{
SimpleLogger().Write(logWARNING) << "Edge: " << edge
2015-04-23 12:53:36 -04:00
<< ",source: " << contracted_edge_list->at(edge).source
<< ", target: " << contracted_edge_list->at(edge).target
<< ", dist: " << current_edge.data.distance;
2014-07-03 07:29:15 -04:00
SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
2015-04-23 12:53:36 -04:00
<< contracted_edge_list->at(edge).source << "/"
2014-07-03 07:29:15 -04:00
<< node_array.size() - 1;
return 1;
}
#endif
hsgr_output_stream.write((char *)&current_edge,
sizeof(StaticGraph<EdgeData>::EdgeArrayEntry));
++number_of_used_edges;
}
2015-04-23 12:53:36 -04:00
return number_of_used_edges;
2014-07-03 07:29:15 -04:00
}
unsigned Prepare::CalculateEdgeChecksum(std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list)
{
RangebasedCRC32 crc32;
if (crc32.using_hardware())
{
SimpleLogger().Write() << "using hardware based CRC32 computation";
}
else
{
SimpleLogger().Write() << "using software based CRC32 computation";
}
const unsigned crc32_value = crc32(*node_based_edge_list);
SimpleLogger().Write() << "CRC32: " << crc32_value;
return crc32_value;
}
2014-07-03 07:29:15 -04:00
/**
\brief Parses command line arguments
\param argc count of arguments
\param argv array of arguments
\param result [out] value for exit return value
\return true if everything is ok, false if need to terminate execution
*/
bool Prepare::ParseArguments(int argc, char *argv[])
{
// declare a group of options that will be allowed only on command line
boost::program_options::options_description generic_options("Options");
generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
2015-01-22 06:19:11 -05:00
"config,c", boost::program_options::value<boost::filesystem::path>(&config_file_path)
->default_value("contractor.ini"),
2014-07-03 07:29:15 -04:00
"Path to a configuration file.");
// declare a group of options that will be allowed both on command line and in config file
boost::program_options::options_description config_options("Configuration");
config_options.add_options()(
"restrictions,r",
boost::program_options::value<boost::filesystem::path>(&restrictions_path),
"Restrictions file in .osrm.restrictions format")(
2015-01-22 06:19:11 -05:00
"profile,p", boost::program_options::value<boost::filesystem::path>(&profile_path)
->default_value("profile.lua"),
2014-07-03 07:29:15 -04:00
"Path to LUA routing profile")(
2015-01-22 06:19:11 -05:00
"threads,t", boost::program_options::value<unsigned int>(&requested_num_threads)
->default_value(tbb::task_scheduler_init::default_num_threads()),
2014-07-03 07:29:15 -04:00
"Number of threads to use");
// hidden options, will be allowed both on command line and in config file, but will not be
// shown to the user
boost::program_options::options_description hidden_options("Hidden options");
hidden_options.add_options()(
"input,i", boost::program_options::value<boost::filesystem::path>(&osrm_input_path),
2014-07-03 07:29:15 -04:00
"Input file in .osm, .osm.bz2 or .osm.pbf format");
// positional option
boost::program_options::positional_options_description positional_options;
positional_options.add("input", 1);
// combine above options for parsing
boost::program_options::options_description cmdline_options;
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
boost::program_options::options_description config_file_options;
config_file_options.add(config_options).add(hidden_options);
boost::program_options::options_description visible_options(
"Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
visible_options.add(generic_options).add(config_options);
// parse command line options
boost::program_options::variables_map option_variables;
boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
.options(cmdline_options)
.positional(positional_options)
.run(),
option_variables);
2015-01-22 06:19:11 -05:00
const auto &temp_config_path = option_variables["config"].as<boost::filesystem::path>();
if (boost::filesystem::is_regular_file(temp_config_path))
{
2015-01-22 06:19:11 -05:00
boost::program_options::store(boost::program_options::parse_config_file<char>(
temp_config_path.string().c_str(), cmdline_options, true),
option_variables);
}
2014-07-03 07:29:15 -04:00
if (option_variables.count("version"))
{
SimpleLogger().Write() << g_GIT_DESCRIPTION;
return false;
}
if (option_variables.count("help"))
{
SimpleLogger().Write() << "\n" << visible_options;
return false;
}
boost::program_options::notify(option_variables);
if (!option_variables.count("restrictions"))
{
restrictions_path = std::string(osrm_input_path.string() + ".restrictions");
2014-07-03 07:29:15 -04:00
}
if (!option_variables.count("input"))
{
SimpleLogger().Write() << "\n" << visible_options;
return false;
}
return true;
}
/**
\brief Setups scripting environment (lua-scripting)
Also initializes speed profile.
*/
void Prepare::SetupScriptingEnvironment(
2015-01-22 06:19:11 -05:00
lua_State *lua_state, EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
2014-07-03 07:29:15 -04:00
{
// open utility libraries string library;
luaL_openlibs(lua_state);
// adjust lua load path
luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
// Now call our function in a lua script
if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
{
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
throw osrm::exception(msg.str());
2014-07-03 07:29:15 -04:00
}
if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
{
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
throw osrm::exception(msg.str());
2014-07-03 07:29:15 -04:00
}
speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
2014-07-03 07:29:15 -04:00
SimpleLogger().Write(logDEBUG)
<< "traffic_signal_penalty: " << speed_profile.traffic_signal_penalty;
2014-07-03 07:29:15 -04:00
if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
{
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
throw osrm::exception(msg.str());
2014-07-03 07:29:15 -04:00
}
speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
2014-07-03 07:29:15 -04:00
speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
}
2014-07-03 07:29:15 -04:00
/**
\brief Build load restrictions from .restriction file
*/
void Prepare::LoadRestrictionMap(const std::unordered_map<NodeID, NodeID> &external_to_internal_node_map,
RestrictionMap &restriction_map)
{
boost::filesystem::ifstream input_stream(restrictions_path, std::ios::in | std::ios::binary);
std::vector<TurnRestriction> restriction_list;
loadRestrictionsFromFile(input_stream, external_to_internal_node_map, restriction_list);
SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
restriction_map = RestrictionMap(restriction_list);
}
/**
\brief Build load node based graph from .osrm file and restrictions from .restrictions file
*/
std::shared_ptr<NodeBasedDynamicGraph>
Prepare::LoadNodeBasedGraph(std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_list,
RestrictionMap &restriction_map,
std::vector<QueryNode>& internal_to_external_node_map)
{
std::vector<ImportEdge> edge_list;
std::unordered_map<NodeID, NodeID> external_to_internal_node_map;
boost::filesystem::ifstream input_stream(osrm_input_path, std::ios::in | std::ios::binary);
NodeID number_of_node_based_nodes = loadNodesFromFile(input_stream,
barrier_node_list, traffic_light_list,
internal_to_external_node_map,
external_to_internal_node_map);
SimpleLogger().Write() << " - " << barrier_node_list.size() << " bollard nodes, "
<< traffic_light_list.size() << " traffic lights";
loadEdgesFromFile(input_stream, external_to_internal_node_map, edge_list);
LoadRestrictionMap(external_to_internal_node_map, restriction_map);
if (edge_list.empty())
{
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return std::shared_ptr<NodeBasedDynamicGraph>();
}
return NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
2014-07-03 07:29:15 -04:00
}
2014-07-03 07:29:15 -04:00
/**
\brief Building an edge-expanded graph from node-based input and turn restrictions
*/
std::pair<std::size_t, std::size_t>
Prepare::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
2014-10-16 11:49:10 -04:00
std::vector<EdgeBasedNode> &node_based_edge_list,
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
2014-07-03 07:29:15 -04:00
{
lua_State *lua_state = luaL_newstate();
luabind::open(lua_state);
EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
SetupScriptingEnvironment(lua_state, speed_profile);
auto barrier_node_list = osrm::make_unique<std::vector<NodeID>>();
auto traffic_light_list = osrm::make_unique<std::vector<NodeID>>();
auto restriction_map = std::make_shared<RestrictionMap>();
auto node_based_graph = LoadNodeBasedGraph(*barrier_node_list, *traffic_light_list, *restriction_map, internal_to_external_node_map);
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
restriction_map,
std::move(barrier_node_list),
std::move(traffic_light_list),
internal_to_external_node_map,
speed_profile);
edge_based_graph_factory.Run(edge_output_path, geometry_output_path, lua_state);
lua_close(lua_state);
2014-07-03 07:29:15 -04:00
2014-10-16 11:49:10 -04:00
const std::size_t number_of_edge_based_nodes =
edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
2014-07-03 07:29:15 -04:00
BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes);
2014-07-03 07:29:15 -04:00
}
/**
\brief Build contracted graph.
*/
void Prepare::ContractGraph(const std::size_t number_of_edge_based_nodes,
DeallocatingVector<EdgeBasedEdge>& edge_based_edge_list,
DeallocatingVector<QueryEdge>& contracted_edge_list)
{
Contractor contractor(number_of_edge_based_nodes, edge_based_edge_list);
contractor.Run();
contractor.GetEdges(contracted_edge_list);
}
2014-07-03 07:29:15 -04:00
/**
\brief Writing info on original (node-based) nodes
*/
void Prepare::WriteNodeMapping(std::unique_ptr<std::vector<QueryNode>> internal_to_external_node_map)
2014-07-03 07:29:15 -04:00
{
boost::filesystem::ofstream node_stream(node_output_path, std::ios::binary);
const unsigned size_of_mapping = internal_to_external_node_map->size();
2014-07-03 07:29:15 -04:00
node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
if (size_of_mapping > 0)
{
node_stream.write((char *) internal_to_external_node_map->data(),
2014-08-29 06:37:07 -04:00
size_of_mapping * sizeof(QueryNode));
2014-07-03 07:29:15 -04:00
}
node_stream.close();
}
/**
\brief Building rtree-based nearest-neighbor data structure
2014-07-03 07:29:15 -04:00
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
2014-07-03 07:29:15 -04:00
*/
void Prepare::BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list, const std::vector<QueryNode>& internal_to_external_node_map)
2014-07-03 07:29:15 -04:00
{
StaticRTree<EdgeBasedNode>(node_based_edge_list, rtree_nodes_output_path.c_str(),
rtree_leafs_output_path.c_str(), internal_to_external_node_map);
2014-07-03 07:29:15 -04:00
}