OSRM plugin for mwm identification

This commit is contained in:
Lev Dragunov 2015-02-04 14:26:40 +03:00 committed by Alex Zolotarev
parent f28135dfe8
commit 62000bcace
11 changed files with 368 additions and 154 deletions

View file

@ -76,6 +76,7 @@ file(GLOB LibOSRMGlob Library/*.cpp)
file(GLOB MapsMeSources mapsme/*.cpp)
file(GLOB MapsMeHeaders mapsme/*.h)
file(GLOB MapsMeGenerator ../../../generator/country_loader.cpp)
set(
OSRMSources
@ -85,6 +86,7 @@ set(
${CoordinateGlob}
${AlgorithmGlob}
${HttpGlob}
${MapsMeGenerator}
)
add_library(COORDINATE OBJECT ${CoordinateGlob})
add_library(FINGERPRINT OBJECT Util/FingerPrint.cpp)
@ -189,7 +191,15 @@ include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(OSRM ${Boost_LIBRARIES})
target_link_libraries(osrm-extract ${Boost_LIBRARIES})
target_link_libraries(osrm-prepare ${Boost_LIBRARIES})
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM)
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM
debug "${CMAKE_SOURCE_DIR}/../../../../omim-build-debug/out/debug/libcoding.a"
"${CMAKE_SOURCE_DIR}/../../../../omim-build-debug/out/debug/libbase.a"
"${CMAKE_SOURCE_DIR}/../../../../omim-build-debug/out/debug/libindexer.a"
"${CMAKE_SOURCE_DIR}/../../../../omim-build-debug/out/debug/libgeometry.a"
general "${CMAKE_SOURCE_DIR}/../../../../omim-build-release/out/release/libcoding.a"
"${CMAKE_SOURCE_DIR}/../../../../omim-build-release/out/release/libindexer.a"
"${CMAKE_SOURCE_DIR}/../../../../omim-build-release/out/release/libgeometry.a"
"${CMAKE_SOURCE_DIR}/../../../../omim-build-release/out/release/libbase.a")
target_link_libraries(osrm-datastore ${Boost_LIBRARIES})
target_link_libraries(osrm-mapsme ${Boost_LIBRARIES} OSRM

View file

@ -41,6 +41,7 @@ namespace boost { namespace interprocess { class named_mutex; } }
#include "../Plugins/NearestPlugin.h"
#include "../Plugins/TimestampPlugin.h"
#include "../Plugins/ViaRoutePlugin.h"
#include "../Plugins/MapsMePlugin.h"
#include "../Server/DataStructures/BaseDataFacade.h"
#include "../Server/DataStructures/InternalDataFacade.h"
#include "../Server/DataStructures/SharedBarriers.h"
@ -79,6 +80,7 @@ OSRM_impl::OSRM_impl(ServerPaths server_paths, const bool use_shared_memory)
RegisterPlugin(new NearestPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new TimestampPlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new ViaRoutePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade));
RegisterPlugin(new MapsMePlugin<BaseDataFacade<QueryEdge::EdgeData>>(query_data_facade, "../../../data/"));
}
OSRM_impl::~OSRM_impl()

View file

@ -0,0 +1,164 @@
#pragma once
#include "BasePlugin.h"
#include "../Algorithms/ObjectToBase64.h"
#include "../DataStructures/JSONContainer.h"
#include "../DataStructures/QueryEdge.h"
#include "../DataStructures/SearchEngine.h"
#include "../Descriptors/BaseDescriptor.h"
#include "../Util/make_unique.hpp"
#include "../Util/StringUtil.h"
#include "../Util/TimingUtil.h"
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <string>
#include <vector>
#include "../../../../generator/country_loader.hpp"
#include "../../../../indexer/mercator.hpp"
class GetMWMNameByPoint
{
class CheckPointInBorder
{
m2::PointD const & m_point;
bool & m_inside;
public:
CheckPointInBorder(m2::PointD const & point, bool & inside) : m_point(point), m_inside(inside) {m_inside=false;}
void operator()(m2::RegionD const & region)
{
if (region.Contains(m_point))
m_inside=true;
}
};
string & m_name;
m2::PointD const & m_point;
public:
GetMWMNameByPoint(string & name, m2::PointD const & point) : m_name(name), m_point(point) {}
void operator() (borders::CountryPolygons const & c)
{
bool inside;
CheckPointInBorder getter(m_point, inside);
c.m_regions.ForEachInRect(m2::RectD(m_point, m_point), getter);
if (inside)
m_name = c.m_name;
}
};
template <class DataFacadeT> class MapsMePlugin final : public BasePlugin
{
private:
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
borders::CountriesContainerT m_countries;
public:
explicit MapsMePlugin(DataFacadeT *facade, std::string const & baseDir) : descriptor_string("mapsme"), facade(facade)
{
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
CHECK(borders::LoadCountriesList(baseDir, m_countries),
("Error loading country polygons files"));
}
virtual ~MapsMePlugin() {}
const std::string GetDescriptor() const final { return descriptor_string; }
void HandleRequest(const RouteParameters &route_parameters, http::Reply &reply) final
{
// check number of parameters
if (2 > route_parameters.coordinates.size())
{
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
RawRouteData raw_route;
raw_route.check_sum = facade->GetCheckSum();
if (std::any_of(begin(route_parameters.coordinates),
end(route_parameters.coordinates),
[&](FixedPointCoordinate coordinate)
{
return !coordinate.isValid();
}))
{
reply = http::Reply::StockReply(http::Reply::badRequest);
return;
}
for (const FixedPointCoordinate &coordinate : route_parameters.coordinates)
{
raw_route.raw_via_node_coordinates.emplace_back(coordinate);
}
std::vector<PhantomNode> phantom_node_vector(raw_route.raw_via_node_coordinates.size());
const bool checksum_OK = (route_parameters.check_sum == raw_route.check_sum);
for (unsigned i = 0; i < raw_route.raw_via_node_coordinates.size(); ++i)
{
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], phantom_node_vector[i]);
if (phantom_node_vector[i].isValid(facade->GetNumberOfNodes()))
{
continue;
}
}
facade->FindPhantomNodeForCoordinate(raw_route.raw_via_node_coordinates[i],
phantom_node_vector[i],
route_parameters.zoom_level);
}
PhantomNodes current_phantom_node_pair;
for (unsigned i = 0; i < phantom_node_vector.size() - 1; ++i)
{
current_phantom_node_pair.source_phantom = phantom_node_vector[i];
current_phantom_node_pair.target_phantom = phantom_node_vector[i + 1];
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
}
search_engine_ptr->shortest_path(
raw_route.segment_end_coordinates, route_parameters.uturns, raw_route);
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
}
reply.status = http::Reply::ok;
//Get mwm names
set<string> usedMwms;
for (auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
{
size_t const n = raw_route.unpacked_path_segments[i].size();
for (size_t j = 0; j < n; ++j)
{
PathData const & path_data = raw_route.unpacked_path_segments[i][j];
FixedPointCoordinate const coord = facade->GetCoordinateOfNode(path_data.node);
string mwmName;
m2::PointD mercatorPoint(MercatorBounds::LonToX(coord.lon), MercatorBounds::LatToY(coord.lat));
GetMWMNameByPoint getter(mwmName, mercatorPoint);
m_countries.ForEachInRect(m2::RectD(mercatorPoint, mercatorPoint), getter);
usedMwms.insert(mwmName);
}
}
JSON::Object json_object;
JSON::Array json_array;
json_array.values.insert(json_array.values.begin(), usedMwms.begin(), usedMwms.end());
json_object.values["used_mwms"] = json_array;
JSON::render(reply.content, json_object);
}
private:
std::string descriptor_string;
DataFacadeT *facade;
};

View file

@ -41,26 +41,4 @@ namespace osm
// drop inner rings
return name[0] != '!';
}
bool LoadBorders(string const & borderFile, vector<m2::RegionD> & outBorders)
{
ifstream stream(borderFile);
string line;
if (!getline(stream, line).good()) // skip title
{
LOG(LERROR, ("Polygon file is empty:", borderFile));
return false;
}
m2::RegionD currentRegion;
while (ReadPolygon(stream, currentRegion, borderFile))
{
CHECK(currentRegion.IsValid(), ("Invalid region in", borderFile));
outBorders.push_back(currentRegion);
currentRegion = m2::RegionD();
}
CHECK(!outBorders.empty(), ("No borders were loaded from", borderFile));
return true;
}
}

View file

@ -8,6 +8,6 @@
namespace osm
{
/// @return false if borderFile can't be opened
bool LoadBorders(string const & borderFile, vector<m2::RegionD> & outBorders);
void GenerateBordersFromOsm(string const & tagAndOptValue, string const & osmFile,
string const & outFile);
}

View file

@ -22,128 +22,59 @@
#include "../std/vector.hpp"
#include "../std/bind.hpp"
#include "../../boost/boost/filesystem.hpp"
namespace fs = boost::filesystem;
namespace borders
{
class PolygonLoader
{
CountryPolygons m_polygons;
m2::RectD m_rect;
CountriesContainerT & m_countries;
public:
PolygonLoader(CountriesContainerT & countries)
: m_countries(countries) {}
void operator() (string const & name, vector<m2::RegionD> const & borders)
{
if (m_polygons.m_name.empty())
m_polygons.m_name = name;
for (m2::RegionD const & border : borders)
{
m2::RectD const rect(border.GetRect());
m_rect.Add(rect);
m_polygons.m_regions.Add(border, rect);
}
}
void Finish()
{
if (!m_polygons.IsEmpty())
{
ASSERT_NOT_EQUAL ( m_rect, m2::RectD::GetEmptyRect(), () );
m_countries.Add(m_polygons, m_rect);
}
m_polygons.Clear();
m_rect.MakeEmpty();
}
};
template <class ToDo>
void ForEachCountry(string const & baseDir, ToDo & toDo)
{
string bordersDir = baseDir + BORDERS_DIR;
ASSERT(fs::exists(bordersDir) && fs::is_directory(bordersDir), ("Cannot read borders directory", bordersDir));
fs::directory_iterator end_iter;
for (fs::directory_iterator dir_iter(bordersDir); dir_iter != end_iter; ++dir_iter)
{
if (fs::is_regular_file(dir_iter->status()) && dir_iter->path().filename().string().find(BORDERS_EXTENSION) != string::npos)
{
vector<m2::RegionD> borders;
if (osm::LoadBorders(dir_iter->path().string(), borders))
{
toDo(dir_iter->path().stem().string(), borders);
toDo.Finish();
}
}
}
}
bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries)
{
countries.Clear();
LOG(LINFO, ("Loading countries."));
PolygonLoader loader(countries);
ForEachCountry(baseDir, loader);
LOG(LINFO, ("Countries loaded:", countries.GetSize()));
return !countries.IsEmpty();
}
class PackedBordersGenerator
{
FilesContainerW m_writer;
string const & m_baseDir;
vector<storage::CountryDef> m_polys;
public:
PackedBordersGenerator(string const & baseDir)
: m_writer(baseDir + PACKED_POLYGONS_FILE)
: m_writer(baseDir + PACKED_POLYGONS_FILE), m_baseDir(baseDir)
{
}
void operator() (string const & name, vector<m2::RegionD> const & borders)
void operator() (string const & name)
{
// use index in vector as tag
FileWriter w = m_writer.GetWriter(strings::to_string(m_polys.size()));
serial::CodingParams cp;
// calc rect
m2::RectD rect;
for (m2::RegionD const & border : borders)
rect.Add(border.GetRect());
// store polygon info
m_polys.push_back(storage::CountryDef(name, rect));
// write polygons as paths
WriteVarUint(w, borders.size());
for (m2::RegionD const & border : borders)
vector<m2::RegionD> borders;
if (borders::LoadBorders(m_baseDir + BORDERS_DIR + name + BORDERS_EXTENSION, borders))
{
typedef vector<m2::PointD> VectorT;
typedef m2::DistanceToLineSquare<m2::PointD> DistanceT;
// use index in vector as tag
FileWriter w = m_writer.GetWriter(strings::to_string(m_polys.size()));
serial::CodingParams cp;
VectorT const & in = border.Data();
VectorT out;
uint32_t const count = static_cast<uint32_t>(borders.size());
/// @todo Choose scale level for simplification.
double const eps = my::sq(scales::GetEpsilonForSimplify(10));
DistanceT dist;
SimplifyNearOptimal(20, in.begin(), in.end(), eps, dist,
AccumulateSkipSmallTrg<DistanceT, m2::PointD>(dist, out, eps));
// calc rect
m2::RectD rect;
for (uint32_t i = 0; i < count; ++i)
rect.Add(borders[i].GetRect());
serial::SaveOuterPath(out, cp, w);
// store polygon info
m_polys.push_back(storage::CountryDef(name, rect));
// write polygons as paths
WriteVarUint(w, count);
for (uint32_t i = 0; i < count; ++i)
{
typedef vector<m2::PointD> VectorT;
typedef m2::DistanceToLineSquare<m2::PointD> DistanceT;
VectorT const & in = borders[i].Data();
VectorT out;
/// @todo Choose scale level for simplification.
double const eps = my::sq(scales::GetEpsilonForSimplify(10));
DistanceT dist;
SimplifyNearOptimal(20, in.begin(), in.end(), eps, dist,
AccumulateSkipSmallTrg<DistanceT, m2::PointD>(dist, out, eps));
serial::SaveOuterPath(out, cp, w);
}
}
}

View file

@ -5,34 +5,9 @@
#include "../std/string.hpp"
#define BORDERS_DIR "borders/"
#define BORDERS_EXTENSION ".poly"
#include "country_loader.hpp"
namespace borders
{
typedef m2::RegionD Region;
typedef m4::Tree<Region> RegionsContainerT;
struct CountryPolygons
{
CountryPolygons(string const & name = "") : m_name(name), m_index(-1) {}
bool IsEmpty() const { return m_regions.IsEmpty(); }
void Clear()
{
m_regions.Clear();
m_name.clear();
m_index = -1;
}
RegionsContainerT m_regions;
string m_name;
mutable int m_index;
};
typedef m4::Tree<CountryPolygons> CountriesContainerT;
bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries);
void GeneratePackedBorders(string const & baseDir);
}

View file

@ -0,0 +1,91 @@
#include "country_loader.hpp"
#include "../base/std_serialization.hpp"
#include "../base/logging.hpp"
#include "../coding/file_reader.hpp"
#include "../coding/file_writer.hpp"
#include "../coding/streams_sink.hpp"
namespace borders
{
bool LoadBorders(string const & borderFile, vector<m2::RegionD> & outBorders)
{
ifstream stream(borderFile);
string line;
if (!getline(stream, line).good()) // skip title
{
LOG(LERROR, ("Polygon file is empty:", borderFile));
return false;
}
m2::RegionD currentRegion;
while (ReadPolygon(stream, currentRegion, borderFile))
{
CHECK(currentRegion.IsValid(), ("Invalid region in", borderFile));
outBorders.push_back(currentRegion);
currentRegion = m2::RegionD();
}
CHECK(!outBorders.empty(), ("No borders were loaded from", borderFile));
return true;
}
class PolygonLoader
{
CountryPolygons m_polygons;
m2::RectD m_rect;
string const & m_baseDir;
CountriesContainerT & m_countries;
public:
PolygonLoader(string const & baseDir, CountriesContainerT & countries)
: m_baseDir(baseDir), m_countries(countries) {}
void operator() (string const & name)
{
if (m_polygons.m_name.empty())
m_polygons.m_name = name;
vector<m2::RegionD> borders;
if (LoadBorders(m_baseDir + BORDERS_DIR + name + BORDERS_EXTENSION, borders))
{
for (size_t i = 0; i < borders.size(); ++i)
{
m2::RectD const rect(borders[i].GetRect());
m_rect.Add(rect);
m_polygons.m_regions.Add(borders[i], rect);
}
}
}
void Finish()
{
if (!m_polygons.IsEmpty())
{
ASSERT_NOT_EQUAL ( m_rect, m2::RectD::GetEmptyRect(), () );
m_countries.Add(m_polygons, m_rect);
}
m_polygons.Clear();
m_rect.MakeEmpty();
}
};
bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries)
{
countries.Clear();
LOG(LINFO, ("Loading countries."));
PolygonLoader loader(baseDir, countries);
ForEachCountry(baseDir, loader);
LOG(LINFO, ("Countries loaded:", countries.GetSize()));
return !countries.IsEmpty();
}
}

View file

@ -0,0 +1,59 @@
#pragma once
#include "../geometry/region2d.hpp"
#include "../geometry/tree4d.hpp"
#include "../std/string.hpp"
#include "../std/fstream.hpp"
#define BORDERS_DIR "borders/"
#define BORDERS_EXTENSION ".poly"
#define POLYGONS_FILE "polygons.lst"
namespace borders
{
typedef m2::RegionD Region;
typedef m4::Tree<Region> RegionsContainerT;
struct CountryPolygons
{
CountryPolygons(string const & name = "") : m_name(name), m_index(-1) {}
bool IsEmpty() const { return m_regions.IsEmpty(); }
void Clear()
{
m_regions.Clear();
m_name.clear();
m_index = -1;
}
RegionsContainerT m_regions;
string m_name;
mutable int m_index;
};
typedef m4::Tree<CountryPolygons> CountriesContainerT;
/// @return false if borderFile can't be opened
bool LoadBorders(string const & borderFile, vector<m2::RegionD> & outBorders);
bool LoadCountriesList(string const & baseDir, CountriesContainerT & countries);
template <class ToDo>
void ForEachCountry(string const & baseDir, ToDo & toDo)
{
ifstream stream((baseDir + POLYGONS_FILE).c_str());
string line;
while (stream.good())
{
std::getline(stream, line);
if (line.empty())
continue;
// in polygons file every country is a separate string
toDo(line);
toDo.Finish();
}
}
}

View file

@ -34,6 +34,7 @@ SOURCES += \
tesselator.cpp \
check_model.cpp \
routing_generator.cpp \
country_loader.cpp \
HEADERS += \
feature_merger.hpp \
@ -64,3 +65,4 @@ HEADERS += \
ways_merger.hpp \
gen_mwm_info.hpp \
routing_generator.hpp \
country_loader.hpp \

View file

@ -2,6 +2,7 @@
#include "../osm_xml_parser.hpp"
#include "../borders_generator.hpp"
#include "../country_loader.hpp"
#include "../../coding/reader.hpp"
#include "../../coding/parse_xml.hpp"
@ -9,6 +10,7 @@
#include "../../coding/file_writer.hpp"
using namespace osm;
using namespace borders;
static char const gOsmXml[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"