osrm-backend/src/tools/components.cpp
Daniel Patterson 50d9632ed7
Upgrade formatting to clang-format 10 (#5895)
* Update formatting tools to clang-format-10

* Reformat using clang-format-10.0.09
2020-11-26 07:21:39 -08:00

205 lines
6.3 KiB
C++

#include "extractor/files.hpp"
#include "extractor/packed_osm_ids.hpp"
#include "extractor/tarjan_scc.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/dynamic_graph.hpp"
#include "util/fingerprint.hpp"
#include "util/log.hpp"
#include "util/static_graph.hpp"
#include "util/typedefs.hpp"
#include <boost/filesystem.hpp>
#include <boost/function_output_iterator.hpp>
#include <tbb/parallel_sort.h>
#include <cstdint>
#include <cstdlib>
#include <algorithm>
#include <fstream>
#include <memory>
#include <ostream>
#include <string>
#include <vector>
namespace osrm
{
namespace tools
{
using TarjanGraph = util::StaticGraph<void>;
using TarjanEdge = util::static_graph_details::SortableEdgeWithData<void>;
std::size_t loadGraph(const std::string &path,
std::vector<util::Coordinate> &coordinate_list,
extractor::PackedOSMIDs &osm_node_ids,
std::vector<TarjanEdge> &graph_edge_list)
{
std::vector<extractor::NodeBasedEdge> edge_list;
std::vector<extractor::NodeBasedEdgeAnnotation> annotation_data;
auto nop = boost::make_function_output_iterator([](auto) {});
extractor::files::readRawNBGraph(
path, nop, nop, coordinate_list, osm_node_ids, edge_list, annotation_data);
// Building a node-based graph
for (const auto &input_edge : edge_list)
{
if (input_edge.source == input_edge.target)
{
continue;
}
if (input_edge.flags.forward)
{
graph_edge_list.emplace_back(input_edge.source, input_edge.target);
}
if (input_edge.flags.backward)
{
graph_edge_list.emplace_back(input_edge.target, input_edge.source);
}
}
return osm_node_ids.size();
}
struct FeatureWriter
{
FeatureWriter(std::ostream &out_) : out(out_)
{
out << "{\"type\":\"FeatureCollection\",\"features\":[";
}
void AddLine(const util::Coordinate from,
const util::Coordinate to,
const OSMNodeID from_id,
const OSMNodeID to_id,
const std::string &type)
{
const auto from_lon = static_cast<double>(util::toFloating(from.lon));
const auto from_lat = static_cast<double>(util::toFloating(from.lat));
const auto to_lon = static_cast<double>(util::toFloating(to.lon));
const auto to_lat = static_cast<double>(util::toFloating(to.lat));
static bool first = true;
if (!first)
{
out << ",";
}
out << "{\"type\":\"Feature\",\"properties\":{\"from\":" << from_id << ","
<< "\"to\":" << to_id << ",\"type\":\"" << type
<< "\"},\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[" << from_lon << ","
<< from_lat << "],[" << to_lon << "," << to_lat << "]]}}";
first = false;
}
~FeatureWriter() { out << "]}" << std::flush; }
std::ostream &out;
};
//
} // namespace tools
} // namespace osrm
int main(int argc, char *argv[])
{
using namespace osrm;
util::LogPolicy::GetInstance().Unmute();
if (argc < 3)
{
util::Log(logWARNING) << "Usage: " << argv[0] << " map.osrm components.geojson";
return EXIT_FAILURE;
}
const std::string inpath{argv[1]};
const std::string outpath{argv[2]};
if (boost::filesystem::exists(outpath))
{
util::Log(logWARNING) << "Components file " << outpath << " already exists";
return EXIT_FAILURE;
}
std::ofstream outfile{outpath};
if (!outfile)
{
util::Log(logWARNING) << "Unable to open components file " << outpath << " for writing";
return EXIT_FAILURE;
}
std::vector<tools::TarjanEdge> graph_edge_list;
std::vector<util::Coordinate> coordinate_list;
extractor::PackedOSMIDs osm_node_ids;
auto number_of_nodes = tools::loadGraph(inpath, coordinate_list, osm_node_ids, graph_edge_list);
tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
const auto graph = std::make_shared<osrm::tools::TarjanGraph>(number_of_nodes, graph_edge_list);
graph_edge_list.clear();
graph_edge_list.shrink_to_fit();
util::Log() << "Starting SCC graph traversal";
extractor::TarjanSCC<tools::TarjanGraph> tarjan{*graph};
tarjan.Run();
util::Log() << "Identified: " << tarjan.GetNumberOfComponents() << " components";
util::Log() << "Identified " << tarjan.GetSizeOneCount() << " size one components";
std::uint64_t total_network_length = 0;
tools::FeatureWriter writer{outfile};
for (const NodeID source : osrm::util::irange(0u, graph->GetNumberOfNodes()))
{
for (const auto current_edge : graph->GetAdjacentEdgeRange(source))
{
const auto target = graph->GetTarget(current_edge);
if (source < target || SPECIAL_EDGEID == graph->FindEdge(target, source))
{
BOOST_ASSERT(current_edge != SPECIAL_EDGEID);
BOOST_ASSERT(source != SPECIAL_NODEID);
BOOST_ASSERT(target != SPECIAL_NODEID);
total_network_length += 100 * util::coordinate_calculation::greatCircleDistance(
coordinate_list[source], coordinate_list[target]);
auto source_component_id = tarjan.GetComponentID(source);
auto target_component_id = tarjan.GetComponentID(target);
auto source_component_size = tarjan.GetComponentSize(source_component_id);
auto target_component_size = tarjan.GetComponentSize(target_component_id);
const auto smallest = std::min(source_component_size, target_component_size);
if (smallest < 1000)
{
auto same_component = source_component_id == target_component_id;
std::string type = same_component ? "inner" : "border";
writer.AddLine(coordinate_list[source],
coordinate_list[target],
osm_node_ids[source],
osm_node_ids[target],
type);
}
}
}
}
util::Log() << "Total network distance: " << (total_network_length / 100 / 1000) << " km";
}