2013-10-11 10:14:59 -04:00
|
|
|
#ifndef EDGE_BASED_NODE_H
|
|
|
|
#define EDGE_BASED_NODE_H
|
|
|
|
|
2013-12-16 11:36:36 -05:00
|
|
|
#include "../Util/MercatorUtil.h"
|
|
|
|
#include "../typedefs.h"
|
2013-10-11 10:14:59 -04:00
|
|
|
|
2013-12-20 07:12:56 -05:00
|
|
|
#include <osrm/Coordinate.h>
|
2013-12-17 11:59:44 -05:00
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
// An EdgeBasedNode represents a node in the edge-expanded graph.
|
2014-02-11 05:42:24 -05:00
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
|
2013-10-11 10:14:59 -04:00
|
|
|
struct EdgeBasedNode {
|
2013-11-22 12:05:47 -05:00
|
|
|
|
2013-10-11 10:14:59 -04:00
|
|
|
EdgeBasedNode() :
|
2014-02-26 09:55:04 -05:00
|
|
|
forward_edge_based_node_id(SPECIAL_NODEID),
|
|
|
|
reverse_edge_based_node_id(SPECIAL_NODEID),
|
|
|
|
u(SPECIAL_NODEID),
|
|
|
|
v(SPECIAL_NODEID),
|
|
|
|
name_id(0),
|
2014-02-28 11:14:38 -05:00
|
|
|
forward_weight(INVALID_EDGE_WEIGHT >> 1),
|
|
|
|
reverse_weight(INVALID_EDGE_WEIGHT >> 1),
|
2014-02-21 10:55:41 -05:00
|
|
|
forward_offset(0),
|
2014-02-26 09:55:04 -05:00
|
|
|
reverse_offset(0),
|
2014-02-28 11:14:38 -05:00
|
|
|
packed_geometry_id(SPECIAL_EDGEID),
|
2014-02-26 09:55:04 -05:00
|
|
|
fwd_segment_position( std::numeric_limits<unsigned short>::max() ),
|
2014-02-28 11:14:38 -05:00
|
|
|
belongsToTinyComponent(false)
|
2014-02-11 05:42:24 -05:00
|
|
|
{ }
|
|
|
|
|
2014-02-27 13:49:53 -05:00
|
|
|
explicit EdgeBasedNode(
|
2014-02-11 05:42:24 -05:00
|
|
|
NodeID forward_edge_based_node_id,
|
|
|
|
NodeID reverse_edge_based_node_id,
|
2014-02-26 09:55:04 -05:00
|
|
|
NodeID u,
|
|
|
|
NodeID v,
|
|
|
|
unsigned name_id,
|
2014-02-11 05:42:24 -05:00
|
|
|
int forward_weight,
|
|
|
|
int reverse_weight,
|
2014-02-21 10:55:41 -05:00
|
|
|
int forward_offset,
|
2014-02-26 09:55:04 -05:00
|
|
|
int reverse_offset,
|
2014-02-28 11:14:38 -05:00
|
|
|
unsigned packed_geometry_id,
|
2014-02-26 09:55:04 -05:00
|
|
|
unsigned short fwd_segment_position,
|
2014-02-28 11:14:38 -05:00
|
|
|
bool belongs_to_tiny_component
|
2014-02-11 05:42:24 -05:00
|
|
|
) :
|
|
|
|
forward_edge_based_node_id(forward_edge_based_node_id),
|
|
|
|
reverse_edge_based_node_id(reverse_edge_based_node_id),
|
2014-02-26 09:55:04 -05:00
|
|
|
u(u),
|
|
|
|
v(v),
|
2014-02-11 05:42:24 -05:00
|
|
|
name_id(name_id),
|
|
|
|
forward_weight(forward_weight),
|
|
|
|
reverse_weight(reverse_weight),
|
2014-02-21 10:55:41 -05:00
|
|
|
forward_offset(forward_offset),
|
2014-02-26 09:55:04 -05:00
|
|
|
reverse_offset(reverse_offset),
|
2014-02-28 11:14:38 -05:00
|
|
|
packed_geometry_id(packed_geometry_id),
|
2014-02-26 09:55:04 -05:00
|
|
|
fwd_segment_position(fwd_segment_position),
|
2014-02-28 11:14:38 -05:00
|
|
|
belongsToTinyComponent(belongs_to_tiny_component)
|
2014-02-27 13:49:53 -05:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(
|
|
|
|
( forward_edge_based_node_id != SPECIAL_NODEID ) ||
|
|
|
|
( reverse_edge_based_node_id != SPECIAL_NODEID )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-02-26 09:55:04 -05:00
|
|
|
inline static double ComputePerpendicularDistance(
|
|
|
|
const FixedPointCoordinate & coord_a,
|
|
|
|
const FixedPointCoordinate & coord_b,
|
2014-03-12 05:24:35 -04:00
|
|
|
// the query location on the line defined by p and q.
|
2013-11-22 12:05:47 -05:00
|
|
|
double ComputePerpendicularDistance(
|
2014-02-26 09:55:04 -05:00
|
|
|
const FixedPointCoordinate & query_location,
|
2014-03-12 05:24:35 -04:00
|
|
|
FixedPointCoordinate & nearest_location,
|
2014-02-26 09:55:04 -05:00
|
|
|
double & r
|
|
|
|
) {
|
2014-01-08 11:18:59 -05:00
|
|
|
BOOST_ASSERT( query_location.isValid() );
|
|
|
|
|
2014-03-12 05:48:54 -04:00
|
|
|
const double epsilon = 1.0/precision;
|
2014-02-11 05:42:24 -05:00
|
|
|
const double y = query_location.lon/COORDINATE_PRECISION;
|
2014-02-26 09:55:04 -05:00
|
|
|
const double a = lat2y(coord_a.lat/COORDINATE_PRECISION);
|
|
|
|
const double b = coord_a.lon/COORDINATE_PRECISION;
|
|
|
|
const double c = lat2y(coord_b.lat/COORDINATE_PRECISION);
|
|
|
|
const double d = coord_b.lon/COORDINATE_PRECISION;
|
2014-02-11 05:42:24 -05:00
|
|
|
double p,q/*,mX*/,nY;
|
|
|
|
if( std::abs(a-c) > std::numeric_limits<double>::epsilon() ){
|
|
|
|
const double m = (d-b)/(c-a); // slope
|
|
|
|
// Projection of (x,y) on line joining (a,b) and (c,d)
|
|
|
|
p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m);
|
|
|
|
q = b + m*(p - a);
|
|
|
|
} else {
|
|
|
|
p = c;
|
|
|
|
q = y;
|
|
|
|
}
|
|
|
|
nY = (d*p - c*q)/(a*d - b*c);
|
2014-03-11 11:40:20 -04:00
|
|
|
|
2014-02-11 05:42:24 -05:00
|
|
|
//discretize the result to coordinate precision. it's a hack!
|
|
|
|
if( std::abs(nY) < (1./COORDINATE_PRECISION) ) {
|
|
|
|
nY = 0.;
|
2013-11-22 12:43:01 -05:00
|
|
|
}
|
2014-03-12 05:24:35 -04:00
|
|
|
|
|
|
|
// p, q : the end points of the underlying edge
|
2014-02-26 09:55:04 -05:00
|
|
|
if( std::isnan(r) ) {
|
|
|
|
r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.;
|
2014-03-11 11:40:20 -04:00
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
// r : query location
|
2014-03-11 11:40:20 -04:00
|
|
|
const Point r(lat2y(query_location.lat/COORDINATE_PRECISION),
|
2014-02-11 05:42:24 -05:00
|
|
|
} else if( std::abs(r-1.) <= std::numeric_limits<double>::epsilon() ) {
|
2014-03-12 08:56:25 -04:00
|
|
|
query_location.lon/COORDINATE_PRECISION);
|
2014-02-26 09:55:04 -05:00
|
|
|
nearest_location.lat = coord_a.lat;
|
|
|
|
nearest_location.lon = coord_a.lon;
|
|
|
|
} else if( r >= 1. ){
|
|
|
|
nearest_location.lat = coord_b.lat;
|
|
|
|
nearest_location.lon = coord_b.lon;
|
|
|
|
} else {
|
|
|
|
// point lies in between
|
2014-02-11 05:42:24 -05:00
|
|
|
nearest_location.lat = y2lat(p)*COORDINATE_PRECISION;
|
2014-03-12 05:24:35 -04:00
|
|
|
nearest_location = ComputeNearestPointOnSegment(foot, ratio);
|
|
|
|
|
|
|
|
BOOST_ASSERT( nearest_location.isValid() );
|
|
|
|
|
|
|
|
// TODO: Replace with euclidean approximation when k-NN search is done
|
|
|
|
// const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
|
|
|
|
const double approximated_distance = FixedPointCoordinate::ApproximateDistance(query_location, nearest_location);
|
|
|
|
|
2014-02-11 05:42:24 -05:00
|
|
|
query_location,
|
|
|
|
nearest_location
|
|
|
|
);
|
2014-03-12 05:24:35 -04:00
|
|
|
BOOST_ASSERT( 0.0 <= approximated_distance );
|
|
|
|
return approximated_distance;
|
|
|
|
}
|
|
|
|
|
2014-02-26 09:55:04 -05:00
|
|
|
static inline FixedPointCoordinate Centroid(
|
|
|
|
const FixedPointCoordinate & a,
|
|
|
|
const FixedPointCoordinate & b
|
|
|
|
) {
|
2014-03-12 05:24:35 -04:00
|
|
|
return other.id < id;
|
2014-02-26 09:55:04 -05:00
|
|
|
//The coordinates of the midpoint are given by:
|
|
|
|
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
|
|
|
|
centroid.lon = (std::min(a.lon, b.lon) + std::max(a.lon, b.lon))/2;
|
|
|
|
centroid.lat = (std::min(a.lat, b.lat) + std::max(a.lat, b.lat))/2;
|
|
|
|
return centroid;
|
2014-03-12 05:24:35 -04:00
|
|
|
}
|
|
|
|
|
2014-02-26 09:55:04 -05:00
|
|
|
bool IsCompressed() {
|
2014-02-28 11:14:38 -05:00
|
|
|
return packed_geometry_id != SPECIAL_EDGEID;
|
2014-03-12 05:24:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the midpoint of the underlying edge.
|
|
|
|
inline FixedPointCoordinate Centroid() const {
|
|
|
|
return FixedPointCoordinate((lat1+lat2)/2, (lon1+lon2)/2);
|
|
|
|
}
|
|
|
|
|
2014-02-11 05:42:24 -05:00
|
|
|
NodeID forward_edge_based_node_id;
|
2014-02-28 11:14:38 -05:00
|
|
|
NodeID reverse_edge_based_node_id; // needed for edge-expanded graph
|
2014-02-26 09:55:04 -05:00
|
|
|
NodeID u;
|
|
|
|
NodeID v;
|
|
|
|
unsigned name_id;
|
|
|
|
int forward_weight;
|
|
|
|
int reverse_weight;
|
|
|
|
int forward_offset;
|
|
|
|
int reverse_offset;
|
|
|
|
unsigned short fwd_segment_position;
|
2014-02-27 13:49:53 -05:00
|
|
|
unsigned short rev_segment_position:14; //TODO: not actually needed!
|
2014-03-12 05:24:35 -04:00
|
|
|
bool belongsToTinyComponent:1;
|
2014-02-11 05:42:24 -05:00
|
|
|
NodeID name_id;
|
2014-03-12 05:24:35 -04:00
|
|
|
|
|
|
|
// The weight of the underlying edge.
|
|
|
|
unsigned weight:31;
|
|
|
|
|
2014-02-11 05:42:24 -05:00
|
|
|
int reverse_weight;
|
2014-03-11 11:40:20 -04:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
typedef std::pair<double,double> Point;
|
2014-03-11 11:40:20 -04:00
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
// Compute the perpendicular foot of point r on the line defined by p and q.
|
2014-03-11 11:40:20 -04:00
|
|
|
Point ComputePerpendicularFoot(const Point &p, const Point &q, const Point &r, double epsilon) const {
|
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
// the projection of r onto the line pq
|
|
|
|
double foot_x, foot_y;
|
|
|
|
|
|
|
|
const bool is_parallel_to_y_axis = std::abs(q.first - p.first) < epsilon;
|
|
|
|
|
|
|
|
if( is_parallel_to_y_axis ) {
|
|
|
|
foot_x = q.first;
|
|
|
|
foot_y = r.second;
|
|
|
|
} else {
|
|
|
|
// the slope of the line through (a|b) and (c|d)
|
|
|
|
const double m = (q.second - p.second) / (q.first - p.first);
|
|
|
|
|
|
|
|
// Projection of (x|y) onto the line joining (a|b) and (c|d).
|
|
|
|
foot_x = ((r.first + (m*r.second)) + (m*m*p.first - m*p.second))/(1.0 + m*m);
|
|
|
|
foot_y = p.second + m*(foot_x - p.first);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Point(foot_x, foot_y);
|
2013-11-22 12:05:47 -05:00
|
|
|
}
|
|
|
|
|
2014-03-11 11:40:20 -04:00
|
|
|
// Compute the ratio of the line segment pr to line segment pq.
|
|
|
|
double ComputeRatio(const Point & p, const Point & q, const Point & r, double epsilon) const {
|
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
const bool is_parallel_to_x_axis = std::abs(q.second-p.second) < epsilon;
|
2014-03-12 08:56:25 -04:00
|
|
|
const bool is_parallel_to_y_axis = std::abs(q.first -p.first ) < epsilon;
|
2014-03-12 05:24:35 -04:00
|
|
|
|
2014-03-11 11:40:20 -04:00
|
|
|
double ratio;
|
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
if( !is_parallel_to_y_axis ) {
|
|
|
|
ratio = (r.first - p.first)/(q.first - p.first);
|
|
|
|
} else if( !is_parallel_to_x_axis ) {
|
|
|
|
ratio = (r.second - p.second)/(q.second - p.second);
|
|
|
|
} else {
|
|
|
|
// (a|b) and (c|d) are essentially the same point
|
|
|
|
// by convention, we set the ratio to 0 in this case
|
|
|
|
//ratio = ((lat2 == query_location.lat) && (lon2 == query_location.lon)) ? 1. : 0.;
|
|
|
|
ratio = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Round to integer if the ratio is close to 0 or 1.
|
|
|
|
if( std::abs(ratio) <= epsilon ) {
|
|
|
|
ratio = 0.0;
|
|
|
|
} else if( std::abs(ratio-1.0) <= epsilon ) {
|
|
|
|
ratio = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ratio;
|
2013-10-11 10:14:59 -04:00
|
|
|
}
|
|
|
|
|
2014-03-11 11:40:20 -04:00
|
|
|
// Computes the point on the segment pq which is nearest to a point r = p + lambda * (q-p).
|
2014-03-12 05:24:35 -04:00
|
|
|
// p and q are the end points of the underlying edge.
|
2014-03-11 11:40:20 -04:00
|
|
|
FixedPointCoordinate ComputeNearestPointOnSegment(const Point & r, double lambda) const {
|
|
|
|
|
2014-03-12 05:24:35 -04:00
|
|
|
if( lambda <= 0.0 ) {
|
|
|
|
return FixedPointCoordinate(lat1, lon1);
|
|
|
|
} else if( lambda >= 1.0 ) {
|
|
|
|
return FixedPointCoordinate(lat2, lon2);
|
|
|
|
}
|
2013-10-11 10:14:59 -04:00
|
|
|
|
2014-03-12 08:56:25 -04:00
|
|
|
// r lies between p and q
|
|
|
|
return FixedPointCoordinate(
|
|
|
|
y2lat(r.first)*COORDINATE_PRECISION,
|
|
|
|
r.second*COORDINATE_PRECISION
|
|
|
|
);
|
2013-10-11 10:14:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2013-11-22 12:05:47 -05:00
|
|
|
#endif //EDGE_BASED_NODE_H
|