move GetBearing(.) function into FixedPointCoordinate

This commit is contained in:
Dennis Luxen 2014-05-18 13:06:00 +02:00
parent a47467f29b
commit 8983c0f927
5 changed files with 837 additions and 813 deletions

View File

@ -1,420 +1,473 @@
/* /*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <osrm/Coordinate.h> #include <osrm/Coordinate.h>
#include "../Util/MercatorUtil.h" #include "../Util/MercatorUtil.h"
#include "../Util/SimpleLogger.h" #include "../Util/SimpleLogger.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include <boost/assert.hpp> #include <boost/assert.hpp>
#ifndef NDEBUG #ifndef NDEBUG
#include <bitset> #include <bitset>
#endif #endif
#include <iostream> #include <iostream>
#include <limits> #include <limits>
FixedPointCoordinate::FixedPointCoordinate() FixedPointCoordinate::FixedPointCoordinate()
: lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min()) : lat(std::numeric_limits<int>::min()), lon(std::numeric_limits<int>::min())
{ {
} }
FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon) FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) : lat(lat), lon(lon)
{ {
#ifndef NDEBUG #ifndef NDEBUG
if (0 != (std::abs(lat) >> 30)) if (0 != (std::abs(lat) >> 30))
{ {
std::bitset<32> y(lat); std::bitset<32> y(lat);
SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y; SimpleLogger().Write(logDEBUG) << "broken lat: " << lat << ", bits: " << y;
} }
if (0 != (std::abs(lon) >> 30)) if (0 != (std::abs(lon) >> 30))
{ {
std::bitset<32> x(lon); std::bitset<32> x(lon);
SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x; SimpleLogger().Write(logDEBUG) << "broken lon: " << lon << ", bits: " << x;
} }
#endif #endif
} }
void FixedPointCoordinate::Reset() void FixedPointCoordinate::Reset()
{ {
lat = std::numeric_limits<int>::min(); lat = std::numeric_limits<int>::min();
lon = std::numeric_limits<int>::min(); lon = std::numeric_limits<int>::min();
} }
bool FixedPointCoordinate::isSet() const bool FixedPointCoordinate::isSet() const
{ {
return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon); return (std::numeric_limits<int>::min() != lat) && (std::numeric_limits<int>::min() != lon);
} }
bool FixedPointCoordinate::isValid() const bool FixedPointCoordinate::isValid() const
{ {
if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION || if (lat > 90 * COORDINATE_PRECISION || lat < -90 * COORDINATE_PRECISION ||
lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION) lon > 180 * COORDINATE_PRECISION || lon < -180 * COORDINATE_PRECISION)
{ {
return false; return false;
} }
return true; return true;
} }
bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const bool FixedPointCoordinate::operator==(const FixedPointCoordinate &other) const
{ {
return lat == other.lat && lon == other.lon; return lat == other.lat && lon == other.lon;
} }
double FixedPointCoordinate::ApproximateDistance(const int lat1, double FixedPointCoordinate::ApproximateDistance(const int lat1,
const int lon1, const int lon1,
const int lat2, const int lat2,
const int lon2) const int lon2)
{ {
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min()); BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
double RAD = 0.017453292519943295769236907684886; double RAD = 0.017453292519943295769236907684886;
double lt1 = lat1 / COORDINATE_PRECISION; double lt1 = lat1 / COORDINATE_PRECISION;
double ln1 = lon1 / COORDINATE_PRECISION; double ln1 = lon1 / COORDINATE_PRECISION;
double lt2 = lat2 / COORDINATE_PRECISION; double lt2 = lat2 / COORDINATE_PRECISION;
double ln2 = lon2 / COORDINATE_PRECISION; double ln2 = lon2 / COORDINATE_PRECISION;
double dlat1 = lt1 * (RAD); double dlat1 = lt1 * (RAD);
double dlong1 = ln1 * (RAD); double dlong1 = ln1 * (RAD);
double dlat2 = lt2 * (RAD); double dlat2 = lt2 * (RAD);
double dlong2 = ln2 * (RAD); double dlong2 = ln2 * (RAD);
double dLong = dlong1 - dlong2; double dLong = dlong1 - dlong2;
double dLat = dlat1 - dlat2; double dLat = dlat1 - dlat2;
double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2); double aHarv = pow(sin(dLat / 2.0), 2.0) + cos(dlat1) * cos(dlat2) * pow(sin(dLong / 2.), 2);
double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv)); double cHarv = 2. * atan2(sqrt(aHarv), sqrt(1.0 - aHarv));
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) // earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) // The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
const double earth = 6372797.560856; const double earth = 6372797.560856;
return earth * cHarv; return earth * cHarv;
} }
double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1, double FixedPointCoordinate::ApproximateDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2) const FixedPointCoordinate &c2)
{ {
return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon); return ApproximateDistance(c1.lat, c1.lon, c2.lat, c2.lon);
} }
double FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1, double FixedPointCoordinate::ApproximateEuclideanDistance(const FixedPointCoordinate &c1,
const FixedPointCoordinate &c2) const FixedPointCoordinate &c2)
{ {
return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon); return ApproximateEuclideanDistance(c1.lat, c1.lon, c2.lat, c2.lon);
} }
double FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1, double FixedPointCoordinate::ApproximateEuclideanDistance(const int lat1,
const int lon1, const int lon1,
const int lat2, const int lat2,
const int lon2) const int lon2)
{ {
BOOST_ASSERT(lat1 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon1 != std::numeric_limits<int>::min()); BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
BOOST_ASSERT(lat2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
BOOST_ASSERT(lon2 != std::numeric_limits<int>::min()); BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
const double RAD = 0.017453292519943295769236907684886; const double RAD = 0.017453292519943295769236907684886;
const double float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD; const double float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
const double float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD; const double float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
const double float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD; const double float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
const double float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD; const double float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;
const double x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.); const double x = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.);
const double y = (float_lat2 - float_lat1); const double y = (float_lat2 - float_lat1);
const double earth_radius = 6372797.560856; const double earth_radius = 6372797.560856;
return sqrt(x * x + y * y) * earth_radius; return sqrt(x * x + y * y) * earth_radius;
} }
// Yuck! Code duplication. This function is also in EgdeBasedNode.h // Yuck! Code duplication. This function is also in EgdeBasedNode.h
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &point, double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &point,
const FixedPointCoordinate &segA, const FixedPointCoordinate &segA,
const FixedPointCoordinate &segB) const FixedPointCoordinate &segB)
{ {
const double x = lat2y(point.lat / COORDINATE_PRECISION); const double x = lat2y(point.lat / COORDINATE_PRECISION);
const double y = point.lon / COORDINATE_PRECISION; const double y = point.lon / COORDINATE_PRECISION;
const double a = lat2y(segA.lat / COORDINATE_PRECISION); const double a = lat2y(segA.lat / COORDINATE_PRECISION);
const double b = segA.lon / COORDINATE_PRECISION; const double b = segA.lon / COORDINATE_PRECISION;
const double c = lat2y(segB.lat / COORDINATE_PRECISION); const double c = lat2y(segB.lat / COORDINATE_PRECISION);
const double d = segB.lon / COORDINATE_PRECISION; const double d = segB.lon / COORDINATE_PRECISION;
double p, q, nY; double p, q, nY;
if (std::abs(a - c) > std::numeric_limits<double>::epsilon()) if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
{ {
const double m = (d - b) / (c - a); // slope const double m = (d - b) / (c - a); // slope
// Projection of (x,y) on line joining (a,b) and (c,d) // Projection of (x,y) on line joining (a,b) and (c,d)
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m); p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
q = b + m * (p - a); q = b + m * (p - a);
} }
else else
{ {
p = c; p = c;
q = y; q = y;
} }
nY = (d * p - c * q) / (a * d - b * c); nY = (d * p - c * q) / (a * d - b * c);
// discretize the result to coordinate precision. it's a hack! // discretize the result to coordinate precision. it's a hack!
if (std::abs(nY) < (1. / COORDINATE_PRECISION)) if (std::abs(nY) < (1. / COORDINATE_PRECISION))
{ {
nY = 0.; nY = 0.;
} }
double r = (p - nY * a) / c; double r = (p - nY * a) / c;
if (std::isnan(r)) if (std::isnan(r))
{ {
r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.; r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.;
} }
else if (std::abs(r) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r) <= std::numeric_limits<double>::epsilon())
{ {
r = 0.; r = 0.;
} }
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon())
{ {
r = 1.; r = 1.;
} }
FixedPointCoordinate nearest_location; FixedPointCoordinate nearest_location;
BOOST_ASSERT(!std::isnan(r)); BOOST_ASSERT(!std::isnan(r));
if (r <= 0.) if (r <= 0.)
{ // point is "left" of edge { // point is "left" of edge
nearest_location.lat = segA.lat; nearest_location.lat = segA.lat;
nearest_location.lon = segA.lon; nearest_location.lon = segA.lon;
} }
else if (r >= 1.) else if (r >= 1.)
{ // point is "right" of edge { // point is "right" of edge
nearest_location.lat = segB.lat; nearest_location.lat = segB.lat;
nearest_location.lon = segB.lon; nearest_location.lon = segB.lon;
} }
else else
{ // point lies in between { // point lies in between
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION; nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
nearest_location.lon = q * COORDINATE_PRECISION; nearest_location.lon = q * COORDINATE_PRECISION;
} }
BOOST_ASSERT(nearest_location.isValid()); BOOST_ASSERT(nearest_location.isValid());
const double approximated_distance = const double approximated_distance =
FixedPointCoordinate::ApproximateDistance(point, nearest_location); FixedPointCoordinate::ApproximateDistance(point, nearest_location);
BOOST_ASSERT(0. <= approximated_distance); BOOST_ASSERT(0. <= approximated_distance);
return approximated_distance; return approximated_distance;
} }
double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &coord_a, double FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &coord_a,
const FixedPointCoordinate &coord_b, const FixedPointCoordinate &coord_b,
const FixedPointCoordinate &query_location, const FixedPointCoordinate &query_location,
FixedPointCoordinate &nearest_location, FixedPointCoordinate &nearest_location,
double &r) double &r)
{ {
BOOST_ASSERT(query_location.isValid()); BOOST_ASSERT(query_location.isValid());
const double x = lat2y(query_location.lat / COORDINATE_PRECISION); const double x = lat2y(query_location.lat / COORDINATE_PRECISION);
const double y = query_location.lon / COORDINATE_PRECISION; const double y = query_location.lon / COORDINATE_PRECISION;
const double a = lat2y(coord_a.lat / COORDINATE_PRECISION); const double a = lat2y(coord_a.lat / COORDINATE_PRECISION);
const double b = coord_a.lon / COORDINATE_PRECISION; const double b = coord_a.lon / COORDINATE_PRECISION;
const double c = lat2y(coord_b.lat / COORDINATE_PRECISION); const double c = lat2y(coord_b.lat / COORDINATE_PRECISION);
const double d = coord_b.lon / COORDINATE_PRECISION; const double d = coord_b.lon / COORDINATE_PRECISION;
double p, q /*,mX*/, nY; double p, q /*,mX*/, nY;
if (std::abs(a - c) > std::numeric_limits<double>::epsilon()) if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
{ {
const double m = (d - b) / (c - a); // slope const double m = (d - b) / (c - a); // slope
// Projection of (x,y) on line joining (a,b) and (c,d) // Projection of (x,y) on line joining (a,b) and (c,d)
p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m); p = ((x + (m * y)) + (m * m * a - m * b)) / (1. + m * m);
q = b + m * (p - a); q = b + m * (p - a);
} }
else else
{ {
p = c; p = c;
q = y; q = y;
} }
nY = (d * p - c * q) / (a * d - b * c); nY = (d * p - c * q) / (a * d - b * c);
// discretize the result to coordinate precision. it's a hack! // discretize the result to coordinate precision. it's a hack!
if (std::abs(nY) < (1. / COORDINATE_PRECISION)) if (std::abs(nY) < (1. / COORDINATE_PRECISION))
{ {
nY = 0.; nY = 0.;
} }
r = (p - nY * a) / c; // These values are actually n/m+n and m/m+n , we need 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 // not calculate the explicit values of m an n as we
// are just interested in the ratio // are just interested in the ratio
if (std::isnan(r)) if (std::isnan(r))
{ {
r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.; r = ((coord_b.lat == query_location.lat) && (coord_b.lon == query_location.lon)) ? 1. : 0.;
} }
else if (std::abs(r) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r) <= std::numeric_limits<double>::epsilon())
{ {
r = 0.; r = 0.;
} }
else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon()) else if (std::abs(r - 1.) <= std::numeric_limits<double>::epsilon())
{ {
r = 1.; r = 1.;
} }
BOOST_ASSERT(!std::isnan(r)); BOOST_ASSERT(!std::isnan(r));
if (r <= 0.) if (r <= 0.)
{ {
nearest_location.lat = coord_a.lat; nearest_location.lat = coord_a.lat;
nearest_location.lon = coord_a.lon; nearest_location.lon = coord_a.lon;
} }
else if (r >= 1.) else if (r >= 1.)
{ {
nearest_location.lat = coord_b.lat; nearest_location.lat = coord_b.lat;
nearest_location.lon = coord_b.lon; nearest_location.lon = coord_b.lon;
} }
else else
{ {
// point lies in between // point lies in between
nearest_location.lat = y2lat(p) * COORDINATE_PRECISION; nearest_location.lat = y2lat(p) * COORDINATE_PRECISION;
nearest_location.lon = q * COORDINATE_PRECISION; nearest_location.lon = q * COORDINATE_PRECISION;
} }
BOOST_ASSERT(nearest_location.isValid()); BOOST_ASSERT(nearest_location.isValid());
// TODO: Replace with euclidean approximation when k-NN search is done // TODO: Replace with euclidean approximation when k-NN search is done
// const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance( // const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance(
const double approximated_distance = const double approximated_distance =
FixedPointCoordinate::ApproximateDistance(query_location, nearest_location); FixedPointCoordinate::ApproximateDistance(query_location, nearest_location);
BOOST_ASSERT(0. <= approximated_distance); BOOST_ASSERT(0. <= approximated_distance);
return approximated_distance; return approximated_distance;
} }
void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output) void FixedPointCoordinate::convertInternalLatLonToString(const int value, std::string &output)
{ {
char buffer[12]; char buffer[12];
buffer[11] = 0; // zero termination buffer[11] = 0; // zero termination
output = printInt<11, 6>(buffer, value); output = printInt<11, 6>(buffer, value);
} }
void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord, void FixedPointCoordinate::convertInternalCoordinateToString(const FixedPointCoordinate &coord,
std::string &output) std::string &output)
{ {
std::string tmp; std::string tmp;
tmp.reserve(23); tmp.reserve(23);
convertInternalLatLonToString(coord.lon, tmp); convertInternalLatLonToString(coord.lon, tmp);
output = tmp; output = tmp;
output += ","; output += ",";
convertInternalLatLonToString(coord.lat, tmp); convertInternalLatLonToString(coord.lat, tmp);
output += tmp; output += tmp;
} }
void void
FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord, FixedPointCoordinate::convertInternalReversedCoordinateToString(const FixedPointCoordinate &coord,
std::string &output) std::string &output)
{ {
std::string tmp; std::string tmp;
tmp.reserve(23); tmp.reserve(23);
convertInternalLatLonToString(coord.lat, tmp); convertInternalLatLonToString(coord.lat, tmp);
output = tmp; output = tmp;
output += ","; output += ",";
convertInternalLatLonToString(coord.lon, tmp); convertInternalLatLonToString(coord.lon, tmp);
output += tmp; output += tmp;
} }
void FixedPointCoordinate::Output(std::ostream &out) const void FixedPointCoordinate::Output(std::ostream &out) const
{ {
out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")"; out << "(" << lat / COORDINATE_PRECISION << "," << lon / COORDINATE_PRECISION << ")";
} }
double FixedPointCoordinate::GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B)
// double PointSegmentDistanceSquared( double px, double py, {
// double p1x, double p1y, double delta_long = DegreeToRadian(B.lon / COORDINATE_PRECISION - A.lon / COORDINATE_PRECISION);
// double p2x, double p2y,
// double& t, const double lat1 = DegreeToRadian(A.lat / COORDINATE_PRECISION);
// double& qx, double& qy) const double lat2 = DegreeToRadian(B.lat / COORDINATE_PRECISION);
// {
// static const double kMinSegmentLenSquared = 0.00000001; // adjust to suit. If you use float, you'll probably want something like 0.000001f const double y = sin(delta_long) * cos(lat2);
// static const double kEpsilon = 1.0E-14; // adjust to suit. If you use floats, you'll probably want something like 1E-7f const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
// double dx = p2x - p1x; double result = RadianToDegree(atan2(y, x));
// double dy = p2y - p1y; while (result < 0.)
// double dp1x = px - p1x; {
// double dp1y = py - p1y; result += 360.;
// const double segLenSquared = (dx * dx) + (dy * dy); }
// if (segLenSquared >= -kMinSegmentLenSquared && segLenSquared <= kMinSegmentLenSquared)
// { while (result >= 360.)
// // segment is a point. {
// qx = p1x; result -= 360.;
// qy = p1y; }
// t = 0.0; return result;
// return ((dp1x * dp1x) + (dp1y * dp1y)); }
// }
// else double FixedPointCoordinate::GetBearing(const FixedPointCoordinate &other) const
// { {
// // Project a line from p to the segment [p1,p2]. By considering the line double delta_long = DegreeToRadian(lon / COORDINATE_PRECISION - other.lon / COORDINATE_PRECISION);
// // extending the segment, parameterized as p1 + (t * (p2 - p1)),
// // we find projection of point p onto the line. const double lat1 = DegreeToRadian(other.lat / COORDINATE_PRECISION);
// // It falls where t = [(p - p1) . (p2 - p1)] / |p2 - p1|^2 const double lat2 = DegreeToRadian(lat / COORDINATE_PRECISION);
// t = ((dp1x * dx) + (dp1y * dy)) / segLenSquared;
// if (t < kEpsilon) const double y = sin(delta_long) * cos(lat2);
// { const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
// // intersects at or to the "left" of first segment vertex (p1x, p1y). If t is approximately 0.0, then double result = RadianToDegree(atan2(y, x));
// // intersection is at p1. If t is less than that, then there is no intersection (i.e. p is not within while (result < 0.)
// // the 'bounds' of the segment) {
// if (t > -kEpsilon) result += 360.;
// { }
// // intersects at 1st segment vertex
// t = 0.0; while (result >= 360.)
// } {
// // set our 'intersection' point to p1. result -= 360.;
// qx = p1x; }
// qy = p1y; return result;
// // Note: If you wanted the ACTUAL intersection point of where the projected lines would intersect if }
// // we were doing PointLineDistanceSquared, then qx would be (p1x + (t * dx)) and qy would be (p1y + (t * dy)).
// } double FixedPointCoordinate::DegreeToRadian(const double degree)
// else if (t > (1.0 - kEpsilon)) {
// { return degree * (M_PI / 180.);
// // intersects at or to the "right" of second segment vertex (p2x, p2y). If t is approximately 1.0, then }
// // intersection is at p2. If t is greater than that, then there is no intersection (i.e. p is not within
// // the 'bounds' of the segment) double FixedPointCoordinate::RadianToDegree(const double radian)
// if (t < (1.0 + kEpsilon)) {
// { return radian * (180. / M_PI);
// // intersects at 2nd segment vertex }
// t = 1.0;
// } // double PointSegmentDistanceSquared( double px, double py,
// // set our 'intersection' point to p2. // double p1x, double p1y,
// qx = p2x; // double p2x, double p2y,
// qy = p2y; // double& t,
// // Note: If you wanted the ACTUAL intersection point of where the projected lines would intersect if // double& qx, double& qy)
// // we were doing PointLineDistanceSquared, then qx would be (p1x + (t * dx)) and qy would be (p1y + (t * dy)). // {
// } // static const double kMinSegmentLenSquared = 0.00000001; // adjust to suit. If you use float, you'll probably want something like 0.000001f
// else // static const double kEpsilon = 1.0E-14; // adjust to suit. If you use floats, you'll probably want something like 1E-7f
// { // double dx = p2x - p1x;
// // The projection of the point to the point on the segment that is perpendicular succeeded and the point // double dy = p2y - p1y;
// // is 'within' the bounds of the segment. Set the intersection point as that projected point. // double dp1x = px - p1x;
// qx = p1x + (t * dx); // double dp1y = py - p1y;
// qy = p1y + (t * dy); // const double segLenSquared = (dx * dx) + (dy * dy);
// } // if (segLenSquared >= -kMinSegmentLenSquared && segLenSquared <= kMinSegmentLenSquared)
// // return the squared distance from p to the intersection point. Note that we return the squared distance // {
// // as an optimization because many times you just need to compare relative distances and the squared values // // segment is a point.
// // works fine for that. If you want the ACTUAL distance, just take the square root of this value. // qx = p1x;
// double dpqx = px - qx; // qy = p1y;
// double dpqy = py - qy; // t = 0.0;
// return ((dpqx * dpqx) + (dpqy * dpqy)); // return ((dp1x * dp1x) + (dp1y * dp1y));
// } // }
// } // else
// {
// public float DistanceOfPointToLine2(PointF p1, PointF p2, PointF p) // // Project a line from p to the segment [p1,p2]. By considering the line
// { // // extending the segment, parameterized as p1 + (t * (p2 - p1)),
// // (y1-y2)x + (x2-x1)y + (x1y2-x2y1) // // we find projection of point p onto the line.
// //d(P,L) = -------------------------------- // // It falls where t = [(p - p1) . (p2 - p1)] / |p2 - p1|^2
// // sqrt( (x2-x1)pow2 + (y2-y1)pow2 ) // t = ((dp1x * dx) + (dp1y * dy)) / segLenSquared;
// if (t < kEpsilon)
// double ch = (p1.Y - p2.Y) * p.X + (p2.X - p1.X) * p.Y + (p1.X * p2.Y - p2.X * p1.Y); // {
// double del = Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2)); // // intersects at or to the "left" of first segment vertex (p1x, p1y). If t is approximately 0.0, then
// double d = ch / del; // // intersection is at p1. If t is less than that, then there is no intersection (i.e. p is not within
// return (float)d; // // the 'bounds' of the segment)
// } // if (t > -kEpsilon)
// {
// // intersects at 1st segment vertex
// t = 0.0;
// }
// // set our 'intersection' point to p1.
// qx = p1x;
// qy = p1y;
// // Note: If you wanted the ACTUAL intersection point of where the projected lines would intersect if
// // we were doing PointLineDistanceSquared, then qx would be (p1x + (t * dx)) and qy would be (p1y + (t * dy)).
// }
// else if (t > (1.0 - kEpsilon))
// {
// // intersects at or to the "right" of second segment vertex (p2x, p2y). If t is approximately 1.0, then
// // intersection is at p2. If t is greater than that, then there is no intersection (i.e. p is not within
// // the 'bounds' of the segment)
// if (t < (1.0 + kEpsilon))
// {
// // intersects at 2nd segment vertex
// t = 1.0;
// }
// // set our 'intersection' point to p2.
// qx = p2x;
// qy = p2y;
// // Note: If you wanted the ACTUAL intersection point of where the projected lines would intersect if
// // we were doing PointLineDistanceSquared, then qx would be (p1x + (t * dx)) and qy would be (p1y + (t * dy)).
// }
// else
// {
// // The projection of the point to the point on the segment that is perpendicular succeeded and the point
// // is 'within' the bounds of the segment. Set the intersection point as that projected point.
// qx = p1x + (t * dx);
// qy = p1y + (t * dy);
// }
// // return the squared distance from p to the intersection point. Note that we return the squared distance
// // as an optimization because many times you just need to compare relative distances and the squared values
// // works fine for that. If you want the ACTUAL distance, just take the square root of this value.
// double dpqx = px - qx;
// double dpqy = py - qy;
// return ((dpqx * dpqx) + (dpqy * dpqy));
// }
// }
// public float DistanceOfPointToLine2(PointF p1, PointF p2, PointF p)
// {
// // (y1-y2)x + (x2-x1)y + (x1y2-x2y1)
// //d(P,L) = --------------------------------
// // sqrt( (x2-x1)pow2 + (y2-y1)pow2 )
// double ch = (p1.Y - p2.Y) * p.X + (p2.X - p1.X) * p.Y + (p1.X * p2.Y - p2.X * p1.Y);
// double del = Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
// double d = ch / del;
// return (float)d;
// }

View File

@ -31,39 +31,6 @@ DescriptionFactory::DescriptionFactory() : entireLength(0) {}
DescriptionFactory::~DescriptionFactory() {} DescriptionFactory::~DescriptionFactory() {}
inline double DescriptionFactory::DegreeToRadian(const double degree) const
{
return degree * (M_PI / 180.);
}
inline double DescriptionFactory::RadianToDegree(const double radian) const
{
return radian * (180. / M_PI);
}
double DescriptionFactory::GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B)
const
{
double delta_long = DegreeToRadian(B.lon / COORDINATE_PRECISION - A.lon / COORDINATE_PRECISION);
const double lat1 = DegreeToRadian(A.lat / COORDINATE_PRECISION);
const double lat2 = DegreeToRadian(B.lat / COORDINATE_PRECISION);
const double y = sin(delta_long) * cos(lat2);
const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long);
double result = RadianToDegree(atan2(y, x));
while (result < 0.)
{
result += 360.;
}
while (result >= 360.)
{
result -= 360.;
}
return result;
}
void DescriptionFactory::SetStartSegment(const PhantomNode &source) void DescriptionFactory::SetStartSegment(const PhantomNode &source)
{ {
start_phantom = source; start_phantom = source;

View File

@ -77,7 +77,6 @@ class DescriptionFactory
std::vector<SegmentInformation> path_description; std::vector<SegmentInformation> path_description;
DescriptionFactory(); DescriptionFactory();
virtual ~DescriptionFactory(); virtual ~DescriptionFactory();
double GetBearing(const FixedPointCoordinate &C, const FixedPointCoordinate &B) const;
JSON::Value AppendUnencodedPolylineString() const; JSON::Value AppendUnencodedPolylineString() const;
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data); void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
void BuildRouteSummary(const double distance, const unsigned time); void BuildRouteSummary(const double distance, const unsigned time);
@ -196,8 +195,7 @@ class DescriptionFactory
{ {
if (path_description[i].necessary) if (path_description[i].necessary)
{ {
const double angle = const double angle = path_description[i].location.GetBearing(path_description[i + 1].location);
GetBearing(path_description[i].location, path_description[i + 1].location);
path_description[i].bearing = angle * 10; path_description[i].bearing = angle * 10;
} }
} }

View File

@ -1,357 +1,356 @@
/* /*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef JSON_DESCRIPTOR_H_ #ifndef JSON_DESCRIPTOR_H_
#define JSON_DESCRIPTOR_H_ #define JSON_DESCRIPTOR_H_
#include "BaseDescriptor.h" #include "BaseDescriptor.h"
#include "DescriptionFactory.h" #include "DescriptionFactory.h"
#include "../Algorithms/ObjectToBase64.h" #include "../Algorithms/ObjectToBase64.h"
#include "../Algorithms/ExtractRouteNames.h" #include "../Algorithms/ExtractRouteNames.h"
#include "../DataStructures/JSONContainer.h" #include "../DataStructures/JSONContainer.h"
#include "../DataStructures/SegmentInformation.h" #include "../DataStructures/SegmentInformation.h"
#include "../DataStructures/TurnInstructions.h" #include "../DataStructures/TurnInstructions.h"
#include "../Util/Azimuth.h" #include "../Util/Azimuth.h"
#include "../Util/StringUtil.h" #include "../Util/StringUtil.h"
#include "../Util/TimingUtil.h" #include "../Util/TimingUtil.h"
#include <algorithm> #include <algorithm>
template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT> template <class DataFacadeT> class JSONDescriptor : public BaseDescriptor<DataFacadeT>
{ {
private: private:
// TODO: initalize in c'tor DataFacadeT *facade;
DataFacadeT *facade; DescriptorConfig config;
DescriptorConfig config; DescriptionFactory description_factory, alternate_description_factory;
DescriptionFactory description_factory, alternate_description_factory; FixedPointCoordinate current;
FixedPointCoordinate current; unsigned entered_restricted_area_count;
unsigned entered_restricted_area_count; struct RoundAbout
struct RoundAbout {
{ RoundAbout() : start_index(INT_MAX), name_id(INT_MAX), leave_at_exit(INT_MAX) {}
RoundAbout() : start_index(INT_MAX), name_id(INT_MAX), leave_at_exit(INT_MAX) {} int start_index;
int start_index; int name_id;
int name_id; int leave_at_exit;
int leave_at_exit; } round_about;
} round_about;
struct Segment
struct Segment {
{ Segment() : name_id(-1), length(-1), position(-1) {}
Segment() : name_id(-1), length(-1), position(-1) {} Segment(int n, int l, int p) : name_id(n), length(l), position(p) {}
Segment(int n, int l, int p) : name_id(n), length(l), position(p) {} int name_id;
int name_id; int length;
int length; int position;
int position; };
}; std::vector<Segment> shortest_path_segments, alternative_path_segments;
std::vector<Segment> shortest_path_segments, alternative_path_segments; std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices;
std::vector<unsigned> shortest_leg_end_indices, alternative_leg_end_indices; ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
public:
public: JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0)
JSONDescriptor(DataFacadeT *facade) : facade(facade), entered_restricted_area_count(0) {
{ shortest_leg_end_indices.emplace_back(0);
shortest_leg_end_indices.emplace_back(0); alternative_leg_end_indices.emplace_back(0);
alternative_leg_end_indices.emplace_back(0); }
}
void SetConfig(const DescriptorConfig &c) { config = c; }
void SetConfig(const DescriptorConfig &c) { config = c; }
unsigned DescribeLeg(const std::vector<PathData> route_leg, const PhantomNodes &leg_phantoms)
unsigned DescribeLeg(const std::vector<PathData> route_leg, const PhantomNodes &leg_phantoms) {
{ unsigned added_element_count = 0;
unsigned added_element_count = 0; // Get all the coordinates for the computed route
// Get all the coordinates for the computed route FixedPointCoordinate current_coordinate;
FixedPointCoordinate current_coordinate; for (const PathData &path_data : route_leg)
for (const PathData &path_data : route_leg) {
{ current_coordinate = facade->GetCoordinateOfNode(path_data.node);
current_coordinate = facade->GetCoordinateOfNode(path_data.node); description_factory.AppendSegment(current_coordinate, path_data);
description_factory.AppendSegment(current_coordinate, path_data); ++added_element_count;
++added_element_count; }
} ++added_element_count;
++added_element_count; BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
BOOST_ASSERT((route_leg.size() + 1) == added_element_count); return added_element_count;
return added_element_count; }
}
void Run(const RawRouteData &raw_route,
void Run(const RawRouteData &raw_route, const PhantomNodes &phantom_nodes,
const PhantomNodes &phantom_nodes, http::Reply &reply)
http::Reply &reply) {
{ JSON::Object json_result;
JSON::Object json_result;
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length) {
{ // We do not need to do much, if there is no route ;-)
// We do not need to do much, if there is no route ;-) json_result.values["status"] = 207;
json_result.values["status"] = 207; json_result.values["status_message"] = "Cannot find route between points";
json_result.values["status_message"] = "Cannot find route between points"; JSON::render(reply.content, json_result);
JSON::render(reply.content, json_result); return;
return; }
}
// check if first segment is non-zero
// check if first segment is non-zero std::string road_name =
std::string road_name = facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id);
facade->GetEscapedNameForNameID(phantom_nodes.source_phantom.name_id);
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
BOOST_ASSERT(raw_route.unpacked_path_segments.size() == raw_route.segment_end_coordinates.size());
raw_route.segment_end_coordinates.size());
description_factory.SetStartSegment(phantom_nodes.source_phantom);
description_factory.SetStartSegment(phantom_nodes.source_phantom); json_result.values["status"] = 0;
json_result.values["status"] = 0; json_result.values["status_message"] = "Found route between points";
json_result.values["status_message"] = "Found route between points";
// for each unpacked segment add the leg to the description
// for each unpacked segment add the leg to the description for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i)
for (unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i) {
{ const int added_segments = DescribeLeg(raw_route.unpacked_path_segments[i],
const int added_segments = DescribeLeg(raw_route.unpacked_path_segments[i], raw_route.segment_end_coordinates[i]);
raw_route.segment_end_coordinates[i]); BOOST_ASSERT(0 < added_segments);
BOOST_ASSERT(0 < added_segments); shortest_leg_end_indices.emplace_back(added_segments + shortest_leg_end_indices.back());
shortest_leg_end_indices.emplace_back(added_segments + shortest_leg_end_indices.back()); }
} description_factory.SetEndSegment(phantom_nodes.target_phantom);
description_factory.SetEndSegment(phantom_nodes.target_phantom); description_factory.Run(facade, config.zoom_level);
description_factory.Run(facade, config.zoom_level);
if (config.geometry)
if (config.geometry) {
{ JSON::Value route_geometry = description_factory.AppendEncodedPolylineString(config.encode_geometry);
JSON::Value route_geometry = description_factory.AppendEncodedPolylineString(config.encode_geometry); json_result.values["route_geometry"] = route_geometry;
json_result.values["route_geometry"] = route_geometry; }
} if (config.instructions)
if (config.instructions) {
{ JSON::Array json_route_instructions;
JSON::Array json_route_instructions; BuildTextualDescription(description_factory,
BuildTextualDescription(description_factory, json_route_instructions,
json_route_instructions, raw_route.shortest_path_length,
raw_route.shortest_path_length, shortest_path_segments);
shortest_path_segments); json_result.values["route_instructions"] = json_route_instructions;
json_result.values["route_instructions"] = json_route_instructions; }
} description_factory.BuildRouteSummary(description_factory.entireLength,
description_factory.BuildRouteSummary(description_factory.entireLength, raw_route.shortest_path_length);
raw_route.shortest_path_length); JSON::Object json_route_summary;
JSON::Object json_route_summary; json_route_summary.values["total_distance"] = description_factory.summary.distance;
json_route_summary.values["total_distance"] = description_factory.summary.distance; json_route_summary.values["total_time"] = description_factory.summary.duration;
json_route_summary.values["total_time"] = description_factory.summary.duration; json_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(description_factory.summary.source_name_id);
json_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(description_factory.summary.source_name_id); json_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(description_factory.summary.target_name_id);
json_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(description_factory.summary.target_name_id); json_result.values["route_summary"] = json_route_summary;
json_result.values["route_summary"] = json_route_summary;
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
JSON::Array json_via_points_array;
JSON::Array json_via_points_array; JSON::Array json_first_coordinate;
JSON::Array json_first_coordinate; json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lat/COORDINATE_PRECISION);
json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lat/COORDINATE_PRECISION); json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lon/COORDINATE_PRECISION);
json_first_coordinate.values.push_back(raw_route.segment_end_coordinates.front().source_phantom.location.lon/COORDINATE_PRECISION); json_via_points_array.values.push_back(json_first_coordinate);
json_via_points_array.values.push_back(json_first_coordinate); for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates) {
{ std::string tmp;
std::string tmp; JSON::Array json_coordinate;
JSON::Array json_coordinate; json_coordinate.values.push_back(nodes.target_phantom.location.lat/COORDINATE_PRECISION);
json_coordinate.values.push_back(nodes.target_phantom.location.lat/COORDINATE_PRECISION); json_coordinate.values.push_back(nodes.target_phantom.location.lon/COORDINATE_PRECISION);
json_coordinate.values.push_back(nodes.target_phantom.location.lon/COORDINATE_PRECISION); json_via_points_array.values.push_back(json_coordinate);
json_via_points_array.values.push_back(json_coordinate); }
} json_result.values["via_points"] = json_via_points_array;
json_result.values["via_points"] = json_via_points_array;
JSON::Array json_via_indices_array;
JSON::Array json_via_indices_array; json_via_indices_array.values.insert(json_via_indices_array.values.end(), shortest_leg_end_indices.begin(), shortest_leg_end_indices.end());
json_via_indices_array.values.insert(json_via_indices_array.values.end(), shortest_leg_end_indices.begin(), shortest_leg_end_indices.end()); json_result.values["via_indices"] = json_via_indices_array;
json_result.values["via_indices"] = json_via_indices_array;
// only one alternative route is computed at this time, so this is hardcoded
// only one alternative route is computed at this time, so this is hardcoded if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) {
{ json_result.values["found_alternative"] = JSON::True();
json_result.values["found_alternative"] = JSON::True(); alternate_description_factory.SetStartSegment(phantom_nodes.source_phantom);
alternate_description_factory.SetStartSegment(phantom_nodes.source_phantom); // Get all the coordinates for the computed route
// Get all the coordinates for the computed route for (const PathData &path_data : raw_route.unpacked_alternative)
for (const PathData &path_data : raw_route.unpacked_alternative) {
{ current = facade->GetCoordinateOfNode(path_data.node);
current = facade->GetCoordinateOfNode(path_data.node); alternate_description_factory.AppendSegment(current, path_data);
alternate_description_factory.AppendSegment(current, path_data); }
} alternate_description_factory.Run(facade, config.zoom_level);
alternate_description_factory.Run(facade, config.zoom_level);
if (config.geometry)
if (config.geometry) {
{ JSON::Value alternate_geometry_string = alternate_description_factory.AppendEncodedPolylineString(config.encode_geometry);
JSON::Value alternate_geometry_string = alternate_description_factory.AppendEncodedPolylineString(config.encode_geometry); JSON::Array json_alternate_geometries_array;
JSON::Array json_alternate_geometries_array; json_alternate_geometries_array.values.push_back(alternate_geometry_string);
json_alternate_geometries_array.values.push_back(alternate_geometry_string); json_result.values["alternative_geometries"] = json_alternate_geometries_array;
json_result.values["alternative_geometries"] = json_alternate_geometries_array; }
} // Generate instructions for each alternative (simulated here)
// Generate instructions for each alternative (simulated here) JSON::Array json_alt_instructions;
JSON::Array json_alt_instructions; JSON::Array json_current_alt_instructions;
JSON::Array json_current_alt_instructions; if (config.instructions)
if (config.instructions) {
{ BuildTextualDescription(alternate_description_factory,
BuildTextualDescription(alternate_description_factory, json_current_alt_instructions,
json_current_alt_instructions, raw_route.alternative_path_length,
raw_route.alternative_path_length, alternative_path_segments);
alternative_path_segments); json_alt_instructions.values.push_back(json_current_alt_instructions);
json_alt_instructions.values.push_back(json_current_alt_instructions); json_result.values["alternative_instructions"] = json_alt_instructions;
json_result.values["alternative_instructions"] = json_alt_instructions; }
} alternate_description_factory.BuildRouteSummary(
alternate_description_factory.BuildRouteSummary( alternate_description_factory.entireLength, raw_route.alternative_path_length);
alternate_description_factory.entireLength, raw_route.alternative_path_length);
JSON::Object json_alternate_route_summary;
JSON::Object json_alternate_route_summary; JSON::Array json_alternate_route_summary_array;
JSON::Array json_alternate_route_summary_array; json_alternate_route_summary.values["total_distance"] = alternate_description_factory.summary.distance;
json_alternate_route_summary.values["total_distance"] = alternate_description_factory.summary.distance; json_alternate_route_summary.values["total_time"] = alternate_description_factory.summary.duration;
json_alternate_route_summary.values["total_time"] = alternate_description_factory.summary.duration; json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.source_name_id);
json_alternate_route_summary.values["start_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.source_name_id); json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.target_name_id);
json_alternate_route_summary.values["end_point"] = facade->GetEscapedNameForNameID(alternate_description_factory.summary.target_name_id); json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
json_alternate_route_summary_array.values.push_back(json_alternate_route_summary); json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
JSON::Array json_altenative_indices_array;
JSON::Array json_altenative_indices_array; json_altenative_indices_array.values.push_back(0);
json_altenative_indices_array.values.push_back(0); json_altenative_indices_array.values.push_back(alternate_description_factory.path_description.size());
json_altenative_indices_array.values.push_back(alternate_description_factory.path_description.size()); json_result.values["alternative_indices"] = json_altenative_indices_array;
json_result.values["alternative_indices"] = json_altenative_indices_array; } else {
} else { json_result.values["found_alternative"] = JSON::False();
json_result.values["found_alternative"] = JSON::False(); }
}
// Get Names for both routes
// Get Names for both routes RouteNames route_names = GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
RouteNames route_names = GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade); JSON::Array json_route_names;
JSON::Array json_route_names; json_route_names.values.push_back(route_names.shortest_path_name_1);
json_route_names.values.push_back(route_names.shortest_path_name_1); json_route_names.values.push_back(route_names.shortest_path_name_2);
json_route_names.values.push_back(route_names.shortest_path_name_2); json_result.values["route_name"] = json_route_names;
json_result.values["route_name"] = json_route_names;
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length) {
{ JSON::Array json_alternate_names_array;
JSON::Array json_alternate_names_array; JSON::Array json_alternate_names;
JSON::Array json_alternate_names; json_alternate_names.values.push_back(route_names.alternative_path_name_1);
json_alternate_names.values.push_back(route_names.alternative_path_name_1); json_alternate_names.values.push_back(route_names.alternative_path_name_2);
json_alternate_names.values.push_back(route_names.alternative_path_name_2); json_alternate_names_array.values.push_back(json_alternate_names);
json_alternate_names_array.values.push_back(json_alternate_names); json_result.values["alternative_names"] = json_alternate_names_array;
json_result.values["alternative_names"] = json_alternate_names_array; }
}
JSON::Object json_hint_object;
JSON::Object json_hint_object; json_hint_object.values["checksum"] = raw_route.check_sum;
json_hint_object.values["checksum"] = raw_route.check_sum; JSON::Array json_location_hint_array;
JSON::Array json_location_hint_array; std::string hint;
std::string hint; for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i)
for (unsigned i = 0; i < raw_route.segment_end_coordinates.size(); ++i) {
{ EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint);
EncodeObjectToBase64(raw_route.segment_end_coordinates[i].source_phantom, hint); json_location_hint_array.values.push_back(hint);
json_location_hint_array.values.push_back(hint); }
} EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint);
EncodeObjectToBase64(raw_route.segment_end_coordinates.back().target_phantom, hint); json_location_hint_array.values.push_back(hint);
json_location_hint_array.values.push_back(hint); json_hint_object.values["locations"] = json_location_hint_array;
json_hint_object.values["locations"] = json_location_hint_array; json_result.values["hint_data"] = json_hint_object;
json_result.values["hint_data"] = json_hint_object;
// render the content to the output array
// render the content to the output array TIMER_START(route_render);
TIMER_START(route_render); JSON::render(reply.content, json_result);
JSON::render(reply.content, json_result); TIMER_STOP(route_render);
TIMER_STOP(route_render); SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render);
SimpleLogger().Write(logDEBUG) << "rendering took: " << TIMER_MSEC(route_render); }
}
// TODO: reorder parameters
// TODO: reorder parameters inline void BuildTextualDescription(DescriptionFactory &description_factory,
inline void BuildTextualDescription(DescriptionFactory &description_factory, JSON::Array & json_instruction_array,
JSON::Array & json_instruction_array, const int route_length,
const int route_length, std::vector<Segment> &route_segments_list)
std::vector<Segment> &route_segments_list) {
{ // Segment information has following format:
// Segment information has following format: //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth] unsigned necessary_segments_running_index = 0;
unsigned necessary_segments_running_index = 0; round_about.leave_at_exit = 0;
round_about.leave_at_exit = 0; round_about.name_id = 0;
round_about.name_id = 0; std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
// Fetch data from Factory and generate a string from it.
// Fetch data from Factory and generate a string from it. for (const SegmentInformation &segment : description_factory.path_description)
for (const SegmentInformation &segment : description_factory.path_description) {
{ JSON::Array json_instruction_row;
JSON::Array json_instruction_row; TurnInstruction current_instruction = segment.turn_instruction;
TurnInstruction current_instruction = segment.turn_instruction; entered_restricted_area_count += (current_instruction != segment.turn_instruction);
entered_restricted_area_count += (current_instruction != segment.turn_instruction); if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
if (TurnInstructionsClass::TurnIsNecessary(current_instruction)) {
{ if (TurnInstruction::EnterRoundAbout == current_instruction)
if (TurnInstruction::EnterRoundAbout == current_instruction) {
{ round_about.name_id = segment.name_id;
round_about.name_id = segment.name_id; round_about.start_index = necessary_segments_running_index;
round_about.start_index = necessary_segments_running_index; }
} else
else {
{ std::string current_turn_instruction;
std::string current_turn_instruction; if (TurnInstruction::LeaveRoundAbout == current_instruction)
if (TurnInstruction::LeaveRoundAbout == current_instruction) {
{ temp_instruction = IntToString(as_integer(TurnInstruction::EnterRoundAbout));
temp_instruction = IntToString(as_integer(TurnInstruction::EnterRoundAbout)); current_turn_instruction += temp_instruction;
current_turn_instruction += temp_instruction; current_turn_instruction += "-";
current_turn_instruction += "-"; temp_instruction = IntToString(round_about.leave_at_exit + 1);
temp_instruction = IntToString(round_about.leave_at_exit + 1); current_turn_instruction += temp_instruction;
current_turn_instruction += temp_instruction; round_about.leave_at_exit = 0;
round_about.leave_at_exit = 0; }
} else
else {
{ temp_instruction = IntToString(as_integer(current_instruction));
temp_instruction = IntToString(as_integer(current_instruction)); current_turn_instruction += temp_instruction;
current_turn_instruction += temp_instruction; }
} json_instruction_row.values.push_back(current_turn_instruction);
json_instruction_row.values.push_back(current_turn_instruction);
json_instruction_row.values.push_back(facade->GetEscapedNameForNameID(segment.name_id));
json_instruction_row.values.push_back(facade->GetEscapedNameForNameID(segment.name_id)); json_instruction_row.values.push_back(std::round(segment.length));
json_instruction_row.values.push_back(std::round(segment.length)); json_instruction_row.values.push_back(necessary_segments_running_index);
json_instruction_row.values.push_back(necessary_segments_running_index); json_instruction_row.values.push_back(round(segment.duration / 10));
json_instruction_row.values.push_back(round(segment.duration / 10)); json_instruction_row.values.push_back(IntToString(segment.length)+"m");
json_instruction_row.values.push_back(IntToString(segment.length)+"m"); int bearing_value = round(segment.bearing / 10.);
int bearing_value = round(segment.bearing / 10.); json_instruction_row.values.push_back(Azimuth::Get(bearing_value));
json_instruction_row.values.push_back(Azimuth::Get(bearing_value)); json_instruction_row.values.push_back(bearing_value);
json_instruction_row.values.push_back(bearing_value);
route_segments_list.emplace_back(
route_segments_list.emplace_back( segment.name_id, segment.length, route_segments_list.size());
segment.name_id, segment.length, route_segments_list.size()); json_instruction_array.values.push_back(json_instruction_row);
json_instruction_array.values.push_back(json_instruction_row); }
} }
} else if (TurnInstruction::StayOnRoundAbout == current_instruction)
else if (TurnInstruction::StayOnRoundAbout == current_instruction) {
{ ++round_about.leave_at_exit;
++round_about.leave_at_exit; }
} if (segment.necessary)
if (segment.necessary) {
{ ++necessary_segments_running_index;
++necessary_segments_running_index; }
} }
}
//TODO: check if this in an invariant
//TODO: check if this in an invariant if (INVALID_EDGE_WEIGHT != route_length)
if (INVALID_EDGE_WEIGHT != route_length) {
{ JSON::Array json_last_instruction_row;
JSON::Array json_last_instruction_row; temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination));
temp_instruction = IntToString(as_integer(TurnInstruction::ReachedYourDestination)); json_last_instruction_row.values.push_back(temp_instruction);
json_last_instruction_row.values.push_back(temp_instruction); json_last_instruction_row.values.push_back("");
json_last_instruction_row.values.push_back(""); json_last_instruction_row.values.push_back(0);
json_last_instruction_row.values.push_back(0); json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
json_last_instruction_row.values.push_back(necessary_segments_running_index - 1); json_last_instruction_row.values.push_back(0);
json_last_instruction_row.values.push_back(0); json_last_instruction_row.values.push_back("0m");
json_last_instruction_row.values.push_back("0m"); json_last_instruction_row.values.push_back(Azimuth::Get(0.0));
json_last_instruction_row.values.push_back(Azimuth::Get(0.0)); json_last_instruction_row.values.push_back(0.);
json_last_instruction_row.values.push_back(0.); json_instruction_array.values.push_back(json_last_instruction_row);
json_instruction_array.values.push_back(json_last_instruction_row); }
} }
} };
};
#endif /* JSON_DESCRIPTOR_H_ */
#endif /* JSON_DESCRIPTOR_H_ */

View File

@ -74,7 +74,14 @@ struct FixedPointCoordinate
FixedPointCoordinate &nearest_location, FixedPointCoordinate &nearest_location,
double &r); double &r);
static double GetBearing(const FixedPointCoordinate &A, const FixedPointCoordinate &B);
double GetBearing(const FixedPointCoordinate &other) const;
void Output(std::ostream &out) const; void Output(std::ostream &out) const;
static double DegreeToRadian(const double degree);
static double RadianToDegree(const double radian);
}; };
inline std::ostream &operator<<(std::ostream &o, FixedPointCoordinate const &c) inline std::ostream &operator<<(std::ostream &o, FixedPointCoordinate const &c)