use floats instead of doubles for distance computations
This commit is contained in:
parent
4aa7420d6a
commit
812cf36d52
@ -120,13 +120,13 @@ double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
float FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2)
|
||||
{
|
||||
return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon);
|
||||
}
|
||||
|
||||
double FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
|
||||
float FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
|
||||
const int lon1,
|
||||
const int lat2,
|
||||
const int lon2)
|
||||
@ -136,15 +136,15 @@ double FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
|
||||
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
|
||||
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
|
||||
|
||||
const double RAD = 0.017453292519943295769236907684886;
|
||||
const double float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
|
||||
const double float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
|
||||
const float RAD = 0.017453292519943295769236907684886;
|
||||
const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
|
||||
const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
|
||||
|
||||
const double x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.);
|
||||
const double y = (float_lat2 - float_lat1);
|
||||
const double earth_radius = 6372797.560856;
|
||||
const float x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.);
|
||||
const float y = (float_lat2 - float_lat1);
|
||||
const float earth_radius = 6372797.560856;
|
||||
return sqrt(x * x + y * y) * earth_radius;
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordi
|
||||
}
|
||||
BOOST_ASSERT(nearest_location.isValid());
|
||||
const double approximated_distance =
|
||||
FixedPointCoordinate::ApproximateDistance(point, nearest_location);
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
@ -269,13 +269,11 @@ double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordi
|
||||
BOOST_ASSERT(!std::isnan(r));
|
||||
if (r <= 0.)
|
||||
{
|
||||
nearest_location.lat = coord_a.lat;
|
||||
nearest_location.lon = coord_a.lon;
|
||||
nearest_location = coord_a;
|
||||
}
|
||||
else if (r >= 1.)
|
||||
{
|
||||
nearest_location.lat = coord_b.lat;
|
||||
nearest_location.lon = coord_b.lon;
|
||||
nearest_location = coord_b;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -288,7 +286,7 @@ double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordi
|
||||
// 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);
|
||||
FixedPointCoordinate::ApproximateEuclideanDistance(query_location, nearest_location);
|
||||
BOOST_ASSERT(0. <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
@ -385,141 +383,6 @@ double FixedPointCoordinate::RadianToDegree(const double radian)
|
||||
return radian * (180. / M_PI);
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
FixedPointCoordinate::ApproximatePerpendicularDistance(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
double &ratio,
|
||||
double precision) const
|
||||
{
|
||||
BOOST_ASSERT(query_location.isValid());
|
||||
|
||||
const double epsilon = 1.0 / precision;
|
||||
|
||||
// p, q : the end points of the underlying edge
|
||||
const Point p(lat2y(coord_a.lat / COORDINATE_PRECISION), coord_a.lon / COORDINATE_PRECISION);
|
||||
const Point q(lat2y(coord_b.lat / COORDINATE_PRECISION), coord_b.lon / COORDINATE_PRECISION);
|
||||
|
||||
// r : query location
|
||||
const Point r(lat2y(query_location.lat / COORDINATE_PRECISION),
|
||||
query_location.lon / COORDINATE_PRECISION);
|
||||
|
||||
const Point foot = ComputePerpendicularFoot(p, q, r, epsilon);
|
||||
ratio = ComputeRatio(p, q, foot, epsilon);
|
||||
|
||||
BOOST_ASSERT(!std::isnan(ratio));
|
||||
|
||||
nearest_location = ComputeNearestPointOnSegment(coord_a, coord_b, 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::ApproximateEuclideanDistance(query_location, nearest_location);
|
||||
|
||||
BOOST_ASSERT(0.0 <= approximated_distance);
|
||||
return approximated_distance;
|
||||
}
|
||||
|
||||
// Compute the perpendicular foot of point r on the line defined by p and q.
|
||||
Point FixedPointCoordinate::ComputePerpendicularFoot(const Point &p,
|
||||
const Point &q,
|
||||
const Point &r,
|
||||
double epsilon) const
|
||||
{
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Compute the ratio of the line segment pr to line segment pq.
|
||||
double FixedPointCoordinate::ComputeRatio(const Point &p,
|
||||
const Point &q,
|
||||
const Point &r,
|
||||
double epsilon) const
|
||||
{
|
||||
|
||||
const bool is_parallel_to_x_axis = std::abs(q.second - p.second) < epsilon;
|
||||
const bool is_parallel_to_y_axis = std::abs(q.first - p.first) < epsilon;
|
||||
|
||||
double ratio;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Computes the point on the segment pq which is nearest to a point r = p + lambda * (q-p).
|
||||
// p and q are the end points of the underlying edge.
|
||||
FixedPointCoordinate FixedPointCoordinate::ComputeNearestPointOnSegment(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const Point &r,
|
||||
double lambda) const
|
||||
{
|
||||
|
||||
if (lambda <= 0.0)
|
||||
{
|
||||
return coord_a;
|
||||
}
|
||||
else if (lambda >= 1.0)
|
||||
{
|
||||
return coord_b;
|
||||
}
|
||||
else
|
||||
{
|
||||
// r lies between p and q
|
||||
return FixedPointCoordinate(y2lat(r.first) * COORDINATE_PRECISION,
|
||||
r.second * COORDINATE_PRECISION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// double PointSegmentDistanceSquared( double px, double py,
|
||||
// double p1x, double p1y,
|
||||
// double p2x, double p2y,
|
||||
|
@ -49,10 +49,10 @@ struct FixedPointCoordinate
|
||||
static double
|
||||
ApproximateDistance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
static double ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
static float ApproximateDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2);
|
||||
|
||||
static double ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
static float ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
|
||||
const FixedPointCoordinate &c2);
|
||||
|
||||
static double
|
||||
@ -84,21 +84,6 @@ struct FixedPointCoordinate
|
||||
|
||||
static double DegreeToRadian(const double degree);
|
||||
static double RadianToDegree(const double radian);
|
||||
|
||||
|
||||
Point ComputePerpendicularFoot(const Point &p, const Point &q, const Point &r, double epsilon) const;
|
||||
double ComputeRatio(const Point & p, const Point & q, const Point & r, double epsilon) const ;
|
||||
FixedPointCoordinate ComputeNearestPointOnSegment(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const Point & r, double lambda) const;
|
||||
double ApproximatePerpendicularDistance(const FixedPointCoordinate &coord_a,
|
||||
const FixedPointCoordinate &coord_b,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate & nearest_location,
|
||||
double & ratio,
|
||||
double precision = COORDINATE_PRECISION
|
||||
) const;
|
||||
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &o, FixedPointCoordinate const &c)
|
||||
|
Loading…
Reference in New Issue
Block a user