move GetBearing(.) function into FixedPointCoordinate
This commit is contained in:
		
							parent
							
								
									a47467f29b
								
							
						
					
					
						commit
						8983c0f927
					
				| @ -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;
 | ||||||
|  | // }
 | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
| @ -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; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -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_ */ |  | ||||||
|  | |||||||
| @ -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) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user