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