osrm-backend/DataStructures/EdgeBasedNode.h

126 lines
3.9 KiB
C++

#ifndef EDGE_BASED_NODE_H
#define EDGE_BASED_NODE_H
#include <cmath>
#include <boost/assert.hpp>
#include "../Util/MercatorUtil.h"
#include "../Util/SimpleLogger.h"
#include "../typedefs.h"
#include <osrm/Coordinate.h>
struct EdgeBasedNode {
EdgeBasedNode() :
id(INT_MAX),
lat1(INT_MAX),
lat2(INT_MAX),
lon1(INT_MAX),
lon2(INT_MAX >> 1),
belongsToTinyComponent(false),
nameID(UINT_MAX),
weight(UINT_MAX >> 1),
ignoreInGrid(false)
{ }
double ComputePerpendicularDistance(
const FixedPointCoordinate& query_location,
FixedPointCoordinate & nearest_location,
double & r
) const {
BOOST_ASSERT( query_location.isValid() );
if( ignoreInGrid ) {
return std::numeric_limits<double>::max();
}
const double x = lat2y(query_location.lat/COORDINATE_PRECISION);
const double y = query_location.lon/COORDINATE_PRECISION;
const double a = lat2y(lat1/COORDINATE_PRECISION);
const double b = lon1/COORDINATE_PRECISION;
const double c = lat2y(lat2/COORDINATE_PRECISION);
const double d = lon2/COORDINATE_PRECISION;
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);
//discretize the result to coordinate precision. it's a hack!
if( std::abs(nY) < (1./COORDINATE_PRECISION) ) {
nY = 0.;
}
r = (p - nY*a)/c;// These values are actually n/m+n and m/m+n , we need
// not calculate the explicit values of m an n as we
// are just interested in the ratio
if( std::isnan(r) ) {
r = ((lat2 == query_location.lat) && (lon2 == query_location.lon)) ? 1. : 0.;
} else if( std::abs(r) <= std::numeric_limits<double>::epsilon() ) {
r = 0.;
} else if( std::abs(r-1.) <= std::numeric_limits<double>::epsilon() ) {
r = 1.;
}
BOOST_ASSERT( !std::isnan(r) );
if( r <= 0. ){
nearest_location.lat = lat1;
nearest_location.lon = lon1;
} else if( r >= 1. ){
nearest_location.lat = lat2;
nearest_location.lon = lon2;
} else {
// point lies in between
nearest_location.lat = y2lat(p)*COORDINATE_PRECISION;
nearest_location.lon = q*COORDINATE_PRECISION;
}
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
);
BOOST_ASSERT( 0. <= approximated_distance );
return approximated_distance;
}
bool operator<(const EdgeBasedNode & other) const {
return other.id < id;
}
bool operator==(const EdgeBasedNode & other) const {
return id == other.id;
}
inline FixedPointCoordinate Centroid() const {
FixedPointCoordinate centroid;
//The coordinates of the midpoint are given by:
//x = (x1 + x2) /2 and y = (y1 + y2) /2.
centroid.lon = (std::min(lon1, lon2) + std::max(lon1, lon2))/2;
centroid.lat = (std::min(lat1, lat2) + std::max(lat1, lat2))/2;
return centroid;
}
NodeID id;
int lat1;
int lat2;
int lon1;
int lon2:31;
bool belongsToTinyComponent:1;
NodeID nameID;
unsigned weight:31;
bool ignoreInGrid:1;
};
#endif //EDGE_BASED_NODE_H