Merge pull request #1347 from Project-OSRM/perpendicular-fix
Fix ComputePerpendicularDistance convinience function
This commit is contained in:
commit
b115764d9c
@ -157,98 +157,16 @@ float FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
|
|||||||
float
|
float
|
||||||
FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &source_coordinate,
|
FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &source_coordinate,
|
||||||
const FixedPointCoordinate &target_coordinate,
|
const FixedPointCoordinate &target_coordinate,
|
||||||
const FixedPointCoordinate &point)
|
const FixedPointCoordinate &query_location)
|
||||||
{
|
{
|
||||||
// initialize values
|
|
||||||
const float x_value = static_cast<float>(mercator::lat2y(point.lat / COORDINATE_PRECISION));
|
|
||||||
const float y_value = point.lon / COORDINATE_PRECISION;
|
|
||||||
float a = static_cast<float>(mercator::lat2y(source_coordinate.lat / COORDINATE_PRECISION));
|
|
||||||
float b = source_coordinate.lon / COORDINATE_PRECISION;
|
|
||||||
float c = static_cast<float>(mercator::lat2y(target_coordinate.lat / COORDINATE_PRECISION));
|
|
||||||
float d = target_coordinate.lon / COORDINATE_PRECISION;
|
|
||||||
float p, q;
|
|
||||||
if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
|
|
||||||
{
|
|
||||||
const float slope = (d - b) / (c - a); // slope
|
|
||||||
// Projection of (x,y) on line joining (a,b) and (c,d)
|
|
||||||
p = ((x_value + (slope * y_value)) + (slope * slope * a - slope * b)) /
|
|
||||||
(1.f + slope * slope);
|
|
||||||
q = b + slope * (p - a);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p = c;
|
|
||||||
q = y_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ratio;
|
float ratio;
|
||||||
bool inverse_ratio = false;
|
|
||||||
|
|
||||||
// straight line segment on equator
|
|
||||||
if (std::abs(c) < std::numeric_limits<float>::epsilon() &&
|
|
||||||
std::abs(a) < std::numeric_limits<float>::epsilon())
|
|
||||||
{
|
|
||||||
ratio = (q - b) / (d - b);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (std::abs(c) < std::numeric_limits<float>::epsilon())
|
|
||||||
{
|
|
||||||
// swap start/end
|
|
||||||
std::swap(a, c);
|
|
||||||
std::swap(b, d);
|
|
||||||
inverse_ratio = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float nY = (d * p - c * q) / (a * d - b * c);
|
|
||||||
// discretize the result to coordinate precision. it's a hack!
|
|
||||||
if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
|
|
||||||
{
|
|
||||||
nY = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute ratio
|
|
||||||
ratio = (p - nY * a) / c;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::isnan(ratio))
|
|
||||||
{
|
|
||||||
ratio = (target_coordinate == point ? 1.f : 0.f);
|
|
||||||
}
|
|
||||||
else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
|
|
||||||
{
|
|
||||||
ratio = 0.f;
|
|
||||||
}
|
|
||||||
else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
|
|
||||||
{
|
|
||||||
ratio = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to do this, if we switched start/end coordinates
|
|
||||||
if (inverse_ratio)
|
|
||||||
{
|
|
||||||
ratio = 1.0f - ratio;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute the nearest location
|
|
||||||
FixedPointCoordinate nearest_location;
|
FixedPointCoordinate nearest_location;
|
||||||
BOOST_ASSERT(!std::isnan(ratio));
|
|
||||||
if (ratio <= 0.f)
|
|
||||||
{ // point is "left" of edge
|
|
||||||
nearest_location = source_coordinate;
|
|
||||||
}
|
|
||||||
else if (ratio >= 1.f)
|
|
||||||
{ // point is "right" of edge
|
|
||||||
nearest_location = target_coordinate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // point lies in between
|
|
||||||
nearest_location.lat = static_cast<int>(mercator::y2lat(p) * COORDINATE_PRECISION);
|
|
||||||
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_ASSERT(nearest_location.is_valid());
|
return ComputePerpendicularDistance(source_coordinate,
|
||||||
return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
|
target_coordinate,
|
||||||
|
query_location,
|
||||||
|
nearest_location,
|
||||||
|
ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
float FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &segment_source,
|
||||||
|
20
unit_tests/data_structures/coordinate.cpp
Normal file
20
unit_tests/data_structures/coordinate.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <osrm/coordinate.hpp>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
// Regression test for bug captured in #1347
|
||||||
|
BOOST_AUTO_TEST_CASE(regression_test_1347)
|
||||||
|
{
|
||||||
|
FixedPointCoordinate u(10 * COORDINATE_PRECISION, -100 * COORDINATE_PRECISION);
|
||||||
|
FixedPointCoordinate v(10.001 * COORDINATE_PRECISION, -100.002 * COORDINATE_PRECISION);
|
||||||
|
FixedPointCoordinate q(10.002 * COORDINATE_PRECISION, -100.001 * COORDINATE_PRECISION);
|
||||||
|
|
||||||
|
float d1 = FixedPointCoordinate::ComputePerpendicularDistance(u, v, q);
|
||||||
|
|
||||||
|
float ratio;
|
||||||
|
FixedPointCoordinate nearest_location;
|
||||||
|
float d2 = FixedPointCoordinate::ComputePerpendicularDistance(u, v, q, nearest_location, ratio);
|
||||||
|
|
||||||
|
BOOST_CHECK_LE(std::abs(d1 - d2), 0.01);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user