2011-11-17 12:56:45 -05:00
|
|
|
/*
|
|
|
|
|
2014-11-27 12:54:20 -05:00
|
|
|
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
2013-10-14 07:42:28 -04:00
|
|
|
All rights reserved.
|
2011-11-17 12:56:45 -05:00
|
|
|
|
2013-10-14 07:42:28 -04:00
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
2011-11-17 12:56:45 -05:00
|
|
|
|
2013-10-14 07:42:28 -04:00
|
|
|
Redistributions of source code must retain the above copyright notice, this list
|
|
|
|
of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright notice, this
|
|
|
|
list of conditions and the following disclaimer in the documentation and/or
|
|
|
|
other materials provided with the distribution.
|
|
|
|
|
|
|
|
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
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
|
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
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
2011-11-17 12:56:45 -05:00
|
|
|
|
|
|
|
#ifndef DESCRIPTIONFACTORY_H_
|
|
|
|
#define DESCRIPTIONFACTORY_H_
|
|
|
|
|
2014-11-28 04:12:08 -05:00
|
|
|
#include "../algorithms/douglas_peucker.hpp"
|
2014-11-28 06:13:18 -05:00
|
|
|
#include "../data_structures/phantom_node.hpp"
|
|
|
|
#include "../data_structures/json_container.hpp"
|
|
|
|
#include "../data_structures/segment_information.hpp"
|
|
|
|
#include "../data_structures/turn_instructions.hpp"
|
2013-06-26 19:48:22 -04:00
|
|
|
#include "../typedefs.h"
|
|
|
|
|
2014-11-24 09:51:52 -05:00
|
|
|
#include <boost/assert.hpp>
|
|
|
|
|
2013-12-20 07:12:56 -05:00
|
|
|
#include <osrm/Coordinate.h>
|
2013-12-17 11:59:44 -05:00
|
|
|
|
2014-11-25 08:52:21 -05:00
|
|
|
#include <cmath>
|
|
|
|
|
2013-10-02 07:05:54 -04:00
|
|
|
#include <limits>
|
2013-06-26 19:48:22 -04:00
|
|
|
#include <vector>
|
2011-11-17 12:56:45 -05:00
|
|
|
|
2014-06-11 06:25:57 -04:00
|
|
|
struct PathData;
|
2011-11-17 12:56:45 -05:00
|
|
|
/* This class is fed with all way segments in consecutive order
|
|
|
|
* and produces the description plus the encoded polyline */
|
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
class DescriptionFactory
|
|
|
|
{
|
2013-11-13 17:33:19 -05:00
|
|
|
DouglasPeucker polyline_generalizer;
|
2013-11-13 15:52:01 -05:00
|
|
|
PhantomNode start_phantom, target_phantom;
|
2012-02-10 11:14:30 -05:00
|
|
|
|
2012-06-11 10:36:33 -04:00
|
|
|
double DegreeToRadian(const double degree) const;
|
|
|
|
double RadianToDegree(const double degree) const;
|
2014-05-02 13:07:55 -04:00
|
|
|
|
2014-05-26 09:31:30 -04:00
|
|
|
std::vector<unsigned> via_indices;
|
|
|
|
|
2014-10-27 12:21:29 -04:00
|
|
|
double entire_length;
|
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
public:
|
|
|
|
struct RouteSummary
|
|
|
|
{
|
2014-05-16 10:09:40 -04:00
|
|
|
unsigned distance;
|
|
|
|
EdgeWeight duration;
|
|
|
|
unsigned source_name_id;
|
|
|
|
unsigned target_name_id;
|
|
|
|
RouteSummary() : distance(0), duration(0), source_name_id(0), target_name_id(0) {}
|
2014-05-02 13:07:55 -04:00
|
|
|
|
2014-05-16 10:09:40 -04:00
|
|
|
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
|
2014-05-02 13:07:55 -04:00
|
|
|
{
|
|
|
|
// compute distance/duration for route summary
|
2014-11-25 08:49:33 -05:00
|
|
|
distance = static_cast<unsigned>(std::round(raw_distance));
|
|
|
|
duration = static_cast<unsigned>(std::round(raw_duration / 10.));
|
2012-02-10 11:14:30 -05:00
|
|
|
}
|
|
|
|
} summary;
|
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
// I know, declaring this public is considered bad. I'm lazy
|
|
|
|
std::vector<SegmentInformation> path_description;
|
2011-11-17 12:56:45 -05:00
|
|
|
DescriptionFactory();
|
2014-05-02 13:07:55 -04:00
|
|
|
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
2012-09-21 16:40:38 -04:00
|
|
|
void BuildRouteSummary(const double distance, const unsigned time);
|
2014-05-27 10:54:10 -04:00
|
|
|
void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
|
2014-09-15 08:23:43 -04:00
|
|
|
void SetEndSegment(const PhantomNode &start_phantom,
|
|
|
|
const bool traversed_in_reverse,
|
|
|
|
const bool is_via_location = false);
|
|
|
|
JSON::Value AppendGeometryString(const bool return_encoded);
|
|
|
|
std::vector<unsigned> const &GetViaIndices() const;
|
2014-05-02 13:07:55 -04:00
|
|
|
|
2014-10-27 12:21:29 -04:00
|
|
|
double get_entire_length() const
|
|
|
|
{
|
|
|
|
return entire_length;
|
|
|
|
}
|
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
template <class DataFacadeT> void Run(const DataFacadeT *facade, const unsigned zoomLevel)
|
|
|
|
{
|
|
|
|
if (path_description.empty())
|
|
|
|
{
|
2013-09-19 12:54:30 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** starts at index 1 */
|
2014-05-02 13:07:55 -04:00
|
|
|
path_description[0].length = 0;
|
2014-08-20 09:47:48 -04:00
|
|
|
for (unsigned i = 1; i < path_description.size(); ++i)
|
2014-03-26 10:28:50 -04:00
|
|
|
{
|
2014-05-02 13:07:55 -04:00
|
|
|
// move down names by one, q&d hack
|
|
|
|
path_description[i - 1].name_id = path_description[i].name_id;
|
|
|
|
path_description[i].length = FixedPointCoordinate::ApproximateEuclideanDistance(
|
|
|
|
path_description[i - 1].location, path_description[i].location);
|
2013-09-19 12:54:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*Simplify turn instructions
|
|
|
|
Input :
|
|
|
|
10. Turn left on B 36 for 20 km
|
|
|
|
11. Continue on B 35; B 36 for 2 km
|
|
|
|
12. Continue on B 36 for 13 km
|
|
|
|
|
|
|
|
becomes:
|
|
|
|
10. Turn left on B 36 for 35 km
|
|
|
|
*/
|
2014-05-02 13:07:55 -04:00
|
|
|
// TODO: rework to check only end and start of string.
|
|
|
|
// stl string is way to expensive
|
|
|
|
|
|
|
|
// unsigned lastTurn = 0;
|
|
|
|
// for(unsigned i = 1; i < path_description.size(); ++i) {
|
|
|
|
// string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
|
2014-05-08 12:04:05 -04:00
|
|
|
// if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
|
2014-05-02 13:07:55 -04:00
|
|
|
// if(std::string::npos != string0.find(string1+";")
|
|
|
|
// || std::string::npos != string0.find(";"+string1)
|
|
|
|
// || std::string::npos != string0.find(string1+" ;")
|
|
|
|
// || std::string::npos != string0.find("; "+string1)
|
|
|
|
// ){
|
|
|
|
// SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
|
|
|
|
// string1;
|
|
|
|
// for(; lastTurn != i; ++lastTurn)
|
|
|
|
// path_description[lastTurn].name_id = path_description[i].name_id;
|
2014-05-08 12:04:05 -04:00
|
|
|
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
2014-05-02 13:07:55 -04:00
|
|
|
// } else if(std::string::npos != string1.find(string0+";")
|
|
|
|
// || std::string::npos != string1.find(";"+string0)
|
|
|
|
// || std::string::npos != string1.find(string0+" ;")
|
|
|
|
// || std::string::npos != string1.find("; "+string0)
|
|
|
|
// ){
|
|
|
|
// SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
|
|
|
|
// string0;
|
|
|
|
// path_description[i].name_id = path_description[i-1].name_id;
|
2014-05-08 12:04:05 -04:00
|
|
|
// path_description[i].turn_instruction = TurnInstruction::NoTurn;
|
2014-05-02 13:07:55 -04:00
|
|
|
// }
|
|
|
|
// }
|
2014-05-08 12:04:05 -04:00
|
|
|
// if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
|
2014-05-02 13:07:55 -04:00
|
|
|
// lastTurn = i;
|
|
|
|
// }
|
|
|
|
// string0 = string1;
|
|
|
|
// }
|
2013-09-19 12:54:30 -04:00
|
|
|
|
2014-06-18 04:44:46 -04:00
|
|
|
float segment_length = 0.;
|
2014-03-26 10:28:50 -04:00
|
|
|
unsigned segment_duration = 0;
|
|
|
|
unsigned segment_start_index = 0;
|
2013-09-19 12:54:30 -04:00
|
|
|
|
2014-08-20 09:47:48 -04:00
|
|
|
for (unsigned i = 1; i < path_description.size(); ++i)
|
2014-05-02 13:07:55 -04:00
|
|
|
{
|
2014-10-27 12:21:29 -04:00
|
|
|
entire_length += path_description[i].length;
|
2014-05-02 13:07:55 -04:00
|
|
|
segment_length += path_description[i].length;
|
|
|
|
segment_duration += path_description[i].duration;
|
|
|
|
path_description[segment_start_index].length = segment_length;
|
|
|
|
path_description[segment_start_index].duration = segment_duration;
|
|
|
|
|
2014-05-08 12:04:05 -04:00
|
|
|
if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
|
2014-05-02 13:07:55 -04:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(path_description[i].necessary);
|
2014-03-26 10:28:50 -04:00
|
|
|
segment_length = 0;
|
|
|
|
segment_duration = 0;
|
|
|
|
segment_start_index = i;
|
2013-09-19 12:54:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
// Post-processing to remove empty or nearly empty path segments
|
|
|
|
if (std::numeric_limits<double>::epsilon() > path_description.back().length)
|
|
|
|
{
|
|
|
|
if (path_description.size() > 2)
|
|
|
|
{
|
|
|
|
path_description.pop_back();
|
|
|
|
path_description.back().necessary = true;
|
2014-05-08 12:04:05 -04:00
|
|
|
path_description.back().turn_instruction = TurnInstruction::NoTurn;
|
2014-05-02 13:07:55 -04:00
|
|
|
target_phantom.name_id = (path_description.end() - 2)->name_id;
|
2013-09-19 12:54:30 -04:00
|
|
|
}
|
|
|
|
}
|
2014-05-18 16:44:19 -04:00
|
|
|
if (std::numeric_limits<double>::epsilon() > path_description.front().length)
|
2014-05-02 13:07:55 -04:00
|
|
|
{
|
|
|
|
if (path_description.size() > 2)
|
|
|
|
{
|
|
|
|
path_description.erase(path_description.begin());
|
2014-05-18 16:44:19 -04:00
|
|
|
path_description.front().turn_instruction = TurnInstruction::HeadOn;
|
|
|
|
path_description.front().necessary = true;
|
|
|
|
start_phantom.name_id = path_description.front().name_id;
|
2013-09-19 12:54:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
// Generalize poly line
|
2014-10-28 19:33:43 -04:00
|
|
|
polyline_generalizer.Run(path_description.begin(), path_description.end(), zoomLevel);
|
2013-09-19 12:54:30 -04:00
|
|
|
|
2014-05-02 13:07:55 -04:00
|
|
|
// fix what needs to be fixed else
|
2014-05-27 06:09:05 -04:00
|
|
|
unsigned necessary_pieces = 0; // a running index that counts the necessary pieces
|
2014-08-20 09:47:48 -04:00
|
|
|
for (unsigned i = 0; i < path_description.size() - 1 && path_description.size() >= 2; ++i)
|
2014-05-02 13:07:55 -04:00
|
|
|
{
|
2014-08-20 09:47:48 -04:00
|
|
|
if (path_description[i].necessary)
|
2014-05-02 13:07:55 -04:00
|
|
|
{
|
2014-08-20 09:47:48 -04:00
|
|
|
++necessary_pieces;
|
|
|
|
if (path_description[i].is_via_location)
|
2014-09-15 08:23:43 -04:00
|
|
|
{ // mark the end of a leg
|
2014-08-20 09:47:48 -04:00
|
|
|
via_indices.push_back(necessary_pieces);
|
2014-05-26 09:31:30 -04:00
|
|
|
}
|
2014-09-15 08:23:43 -04:00
|
|
|
const double angle =
|
|
|
|
path_description[i + 1].location.GetBearing(path_description[i].location);
|
2014-08-20 09:47:48 -04:00
|
|
|
path_description[i].bearing = static_cast<unsigned>(angle * 10);
|
2013-09-19 12:54:30 -04:00
|
|
|
}
|
|
|
|
}
|
2014-09-15 08:23:43 -04:00
|
|
|
via_indices.push_back(necessary_pieces + 1);
|
2014-05-26 09:31:30 -04:00
|
|
|
BOOST_ASSERT(via_indices.size() >= 2);
|
2014-05-26 10:03:08 -04:00
|
|
|
// BOOST_ASSERT(0 != necessary_pieces || path_description.empty());
|
2013-09-19 12:54:30 -04:00
|
|
|
return;
|
|
|
|
}
|
2011-11-22 10:47:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* DESCRIPTIONFACTORY_H_ */
|