Direct edges in contractor correctly and add better graph validation.

This commit is contained in:
Patrick Niklaus
2015-05-24 17:25:38 +02:00
parent aba3ec692f
commit 2777d53a12
4 changed files with 232 additions and 233 deletions
+87 -68
View File
@@ -184,6 +184,7 @@ void ExtractionContainers::PrepareEdges()
{
if (edge_iterator->result.source < node_iterator->node_id)
{
edge_iterator->result.source = SPECIAL_NODEID;
++edge_iterator;
continue;
}
@@ -193,6 +194,15 @@ void ExtractionContainers::PrepareEdges()
continue;
}
// remove loops
if (edge_iterator->result.source == edge_iterator->result.target)
{
edge_iterator->result.source = SPECIAL_NODEID;
edge_iterator->result.target = SPECIAL_NODEID;
++edge_iterator;
continue;
}
BOOST_ASSERT(edge_iterator->result.source == node_iterator->node_id);
// assign new node id
@@ -222,13 +232,16 @@ void ExtractionContainers::PrepareEdges()
edge_iterator = all_edges_list.begin();
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
{
// skip all invalid edges
if (edge_iterator->result.source == SPECIAL_NODEID)
{
++edge_iterator;
continue;
}
if (edge_iterator->result.target < node_iterator->node_id)
{
// mark edge as invalid
edge_iterator->result.source = SPECIAL_NODEID;
edge_iterator->result.target = SPECIAL_NODEID;
// FIXME we are skipping edges here: That means the data is broken!
++edge_iterator;
continue;
}
@@ -237,58 +250,50 @@ void ExtractionContainers::PrepareEdges()
++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);
BOOST_ASSERT(edge_iterator->weight_data.speed >= 0);
BOOST_ASSERT(edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min());
BOOST_ASSERT(edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min());
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 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);
auto& edge = edge_iterator->result;
edge.weight = std::max(1, (int)std::floor(weight + .5));
// assign new node id
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
edge.target = id_iter->second;
// if source id > target id -> swap
if (edge.source > edge.target)
const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
switch (data.type)
{
std::swap(edge.source, edge.target);
// std::swap does not work with bit-fields
bool temp = edge.forward;
edge.forward = edge.backward;
edge.backward = temp;
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;
case InternalExtractorEdge::WeightType::INVALID:
osrm::exception("invalid weight type");
}
}
else
{
// mark edge as invalid
edge_iterator->result.source = SPECIAL_NODEID;
edge_iterator->result.target = SPECIAL_NODEID;
return -1.0;
}(edge_iterator->weight_data);
// FIXME we should print a warning here.
auto& edge = edge_iterator->result;
edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
// assign new node id
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
edge.target = id_iter->second;
// orient edges consistently: source id < target id
// important for multi-edge removal
if (edge.source > edge.target)
{
std::swap(edge.source, edge.target);
// std::swap does not work with bit-fields
bool temp = edge.forward;
edge.forward = edge.backward;
edge.backward = temp;
}
++edge_iterator;
}
@@ -303,13 +308,18 @@ void ExtractionContainers::PrepareEdges()
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s" << std::endl;
BOOST_ASSERT(all_edges_list.size() > 0);
for (unsigned i = 1; i < all_edges_list.size();)
for (unsigned i = 0; i < all_edges_list.size();)
{
// only invalid edges left
if (all_edges_list[i].result.source == SPECIAL_NODEID)
{
break;
}
// skip invalid edges
if (all_edges_list[i].result.target == SPECIAL_NODEID)
{
continue;
}
unsigned start_idx = i;
NodeID source = all_edges_list[i].result.source;
@@ -320,6 +330,7 @@ void ExtractionContainers::PrepareEdges()
unsigned min_forward_idx = std::numeric_limits<unsigned>::max();
unsigned min_backward_idx = std::numeric_limits<unsigned>::max();
// find minimal edge in both directions
while (all_edges_list[i].result.source == source &&
all_edges_list[i].result.target == target)
{
@@ -338,26 +349,34 @@ void ExtractionContainers::PrepareEdges()
BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() || min_forward_idx < i);
BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() || min_backward_idx < i);
BOOST_ASSERT(min_backward_idx != std::numeric_limits<unsigned>::max() ||
min_forward_idx != std::numeric_limits<unsigned>::max());
// reset direction for both edges
if (min_forward_idx != std::numeric_limits<unsigned>::max())
if (min_backward_idx == min_forward_idx)
{
all_edges_list[min_forward_idx].result.forward = false;
all_edges_list[min_forward_idx].result.backward = false;
}
if (min_backward_idx != std::numeric_limits<unsigned>::max())
{
all_edges_list[min_backward_idx].result.forward = false;
all_edges_list[min_backward_idx].result.backward = false;
}
// set directions that were chosen as min
// note that this needs to come after the ifs above, since
// the minimal forward and backward edge can be the same
if (min_forward_idx != std::numeric_limits<unsigned>::max())
all_edges_list[min_forward_idx].result.is_split = false;
all_edges_list[min_forward_idx].result.forward = true;
if (min_backward_idx != std::numeric_limits<unsigned>::max())
all_edges_list[min_backward_idx].result.backward = true;
all_edges_list[min_forward_idx].result.backward = true;
}
else
{
bool has_forward = min_forward_idx != std::numeric_limits<unsigned>::max();
bool has_backward = min_backward_idx != std::numeric_limits<unsigned>::max();
if (has_forward)
{
all_edges_list[min_forward_idx].result.forward = true;
all_edges_list[min_forward_idx].result.backward = false;
all_edges_list[min_forward_idx].result.is_split = has_backward;
}
if (has_backward)
{
std::swap(all_edges_list[min_backward_idx].result.source,
all_edges_list[min_backward_idx].result.target);
all_edges_list[min_backward_idx].result.forward = true;
all_edges_list[min_backward_idx].result.backward = false;
all_edges_list[min_backward_idx].result.is_split = has_forward;
}
}
// invalidate all unused edges
for (unsigned j = start_idx; j < i; j++)