Move files in src/ include/
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONTRACTOR_OPTIONS_HPP
|
||||
#define CONTRACTOR_OPTIONS_HPP
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class return_code : unsigned
|
||||
{
|
||||
ok,
|
||||
fail,
|
||||
exit
|
||||
};
|
||||
|
||||
struct ContractorConfig
|
||||
{
|
||||
ContractorConfig() noexcept : requested_num_threads(0) {}
|
||||
|
||||
boost::filesystem::path config_file_path;
|
||||
boost::filesystem::path osrm_input_path;
|
||||
boost::filesystem::path profile_path;
|
||||
|
||||
std::string level_output_path;
|
||||
std::string core_output_path;
|
||||
std::string graph_output_path;
|
||||
std::string edge_based_graph_path;
|
||||
|
||||
std::string edge_segment_lookup_path;
|
||||
std::string edge_penalty_path;
|
||||
bool use_cached_priority;
|
||||
|
||||
unsigned requested_num_threads;
|
||||
|
||||
//A percentage of vertices that will be contracted for the hierarchy.
|
||||
//Offers a trade-off between preprocessing and query time.
|
||||
//The remaining vertices form the core of the hierarchy
|
||||
//(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
|
||||
double core_factor;
|
||||
|
||||
std::string segment_speed_lookup_path;
|
||||
|
||||
#ifdef DEBUG_GEOMETRY
|
||||
std::string debug_geometry_path;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ContractorOptions
|
||||
{
|
||||
static return_code ParseArguments(int argc, char *argv[], ContractorConfig &extractor_config);
|
||||
|
||||
static void GenerateOutputFilesNames(ContractorConfig &extractor_config);
|
||||
};
|
||||
|
||||
#endif // EXTRACTOR_OPTIONS_HPP
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_BASED_CRC32_H
|
||||
#define ITERATOR_BASED_CRC32_H
|
||||
|
||||
#if defined(__x86_64__) && !defined(__MINGW64__)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
|
||||
#include <iterator>
|
||||
|
||||
class IteratorbasedCRC32
|
||||
{
|
||||
public:
|
||||
bool using_hardware() const { return use_hardware_implementation; }
|
||||
|
||||
IteratorbasedCRC32() : crc(0) { use_hardware_implementation = detect_hardware_support(); }
|
||||
|
||||
template <class Iterator> unsigned operator()(Iterator iter, const Iterator end)
|
||||
{
|
||||
unsigned crc = 0;
|
||||
while (iter != end)
|
||||
{
|
||||
using value_type = typename std::iterator_traits<Iterator>::value_type;
|
||||
const char *data = reinterpret_cast<const char *>(&(*iter));
|
||||
|
||||
if (use_hardware_implementation)
|
||||
{
|
||||
crc = compute_in_hardware(data, sizeof(value_type));
|
||||
}
|
||||
else
|
||||
{
|
||||
crc = compute_in_software(data, sizeof(value_type));
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
private:
|
||||
bool detect_hardware_support() const
|
||||
{
|
||||
static const int sse42_bit = 0x00100000;
|
||||
const unsigned ecx = cpuid();
|
||||
const bool sse42_found = (ecx & sse42_bit) != 0;
|
||||
return sse42_found;
|
||||
}
|
||||
|
||||
unsigned compute_in_software(const char *str, unsigned len)
|
||||
{
|
||||
crc_processor.process_bytes(str, len);
|
||||
return crc_processor.checksum();
|
||||
}
|
||||
|
||||
// adapted from http://byteworm.com/2010/10/13/crc32/
|
||||
unsigned compute_in_hardware(const char *str, unsigned len)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
unsigned q = len / sizeof(unsigned);
|
||||
unsigned r = len % sizeof(unsigned);
|
||||
unsigned *p = (unsigned *)str;
|
||||
|
||||
// crc=0;
|
||||
while (q--)
|
||||
{
|
||||
__asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
: "=S"(crc)
|
||||
: "0"(crc), "c"(*p));
|
||||
++p;
|
||||
}
|
||||
|
||||
str = reinterpret_cast<char *>(p);
|
||||
while (r--)
|
||||
{
|
||||
__asm__ __volatile__(".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;"
|
||||
: "=S"(crc)
|
||||
: "0"(crc), "c"(*str));
|
||||
++str;
|
||||
}
|
||||
#endif
|
||||
return crc;
|
||||
}
|
||||
|
||||
inline unsigned cpuid() const
|
||||
{
|
||||
unsigned eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
// on X64 this calls hardware cpuid(.) instr. otherwise a dummy impl.
|
||||
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
return ecx;
|
||||
}
|
||||
|
||||
#if defined(__MINGW64__) || defined(_MSC_VER) || !defined(__x86_64__)
|
||||
inline void
|
||||
__get_cpuid(int param, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) const
|
||||
{
|
||||
*ecx = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> crc_processor;
|
||||
unsigned crc;
|
||||
bool use_hardware_implementation;
|
||||
};
|
||||
|
||||
struct RangebasedCRC32
|
||||
{
|
||||
template <typename Iteratable> unsigned operator()(const Iteratable &iterable)
|
||||
{
|
||||
return crc32(std::begin(iterable), std::end(iterable));
|
||||
}
|
||||
|
||||
bool using_hardware() const { return crc32.using_hardware(); }
|
||||
|
||||
private:
|
||||
IteratorbasedCRC32 crc32;
|
||||
};
|
||||
|
||||
#endif /* ITERATOR_BASED_CRC32_H */
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PROCESSING_CHAIN_HPP
|
||||
#define PROCESSING_CHAIN_HPP
|
||||
|
||||
#include "contractor.hpp"
|
||||
#include "contractor_options.hpp"
|
||||
#include "../data_structures/query_edge.hpp"
|
||||
#include "../data_structures/static_graph.hpp"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
|
||||
struct SpeedProfileProperties;
|
||||
struct EdgeBasedNode;
|
||||
struct lua_State;
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
\brief class of 'prepare' utility.
|
||||
*/
|
||||
class Prepare
|
||||
{
|
||||
public:
|
||||
using EdgeData = QueryEdge::EdgeData;
|
||||
|
||||
explicit Prepare(ContractorConfig contractor_config) : config(std::move(contractor_config)) {}
|
||||
Prepare(const Prepare &) = delete;
|
||||
~Prepare();
|
||||
|
||||
int Run();
|
||||
|
||||
protected:
|
||||
void ContractGraph(const unsigned max_edge_id,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
DeallocatingVector<QueryEdge> &contracted_edge_list,
|
||||
std::vector<bool> &is_core_node,
|
||||
std::vector<float> &node_levels) const;
|
||||
void WriteCoreNodeMarker(std::vector<bool> &&is_core_node) const;
|
||||
void WriteNodeLevels(std::vector<float> &&node_levels) const;
|
||||
void ReadNodeLevels(std::vector<float> &contraction_order) const;
|
||||
std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
|
||||
const DeallocatingVector<QueryEdge> &contracted_edge_list);
|
||||
void FindComponents(unsigned max_edge_id,
|
||||
const DeallocatingVector<EdgeBasedEdge> &edges,
|
||||
std::vector<EdgeBasedNode> &nodes) const;
|
||||
|
||||
private:
|
||||
ContractorConfig config;
|
||||
std::size_t LoadEdgeExpandedGraph(const std::string &edge_based_graph_path,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &edge_segment_lookup_path,
|
||||
const std::string &edge_penalty_path,
|
||||
const std::string &segment_speed_path);
|
||||
};
|
||||
|
||||
#endif // PROCESSING_CHAIN_HPP
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERYEDGE_HPP
|
||||
#define QUERYEDGE_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
struct QueryEdge
|
||||
{
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
struct EdgeData
|
||||
{
|
||||
EdgeData() : id(0), shortcut(false), distance(0), forward(false), backward(false) {}
|
||||
|
||||
template <class OtherT> EdgeData(const OtherT &other)
|
||||
{
|
||||
distance = other.distance;
|
||||
shortcut = other.shortcut;
|
||||
id = other.id;
|
||||
forward = other.forward;
|
||||
backward = other.backward;
|
||||
}
|
||||
NodeID id : 31;
|
||||
bool shortcut : 1;
|
||||
int distance : 30;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
} data;
|
||||
|
||||
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
|
||||
|
||||
QueryEdge(NodeID source, NodeID target, EdgeData data)
|
||||
: source(source), target(target), data(std::move(data))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const QueryEdge &rhs) const
|
||||
{
|
||||
return std::tie(source, target) < std::tie(rhs.source, rhs.target);
|
||||
}
|
||||
|
||||
bool operator==(const QueryEdge &right) const
|
||||
{
|
||||
return (source == right.source && target == right.target &&
|
||||
data.distance == right.data.distance && data.shortcut == right.data.shortcut &&
|
||||
data.forward == right.data.forward && data.backward == right.data.backward &&
|
||||
data.id == right.data.id);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUERYEDGE_HPP
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_MEMORY_FACTORY_HPP
|
||||
#define SHARED_MEMORY_FACTORY_HPP
|
||||
|
||||
#include "../util/osrm_exception.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#ifndef WIN32
|
||||
#include <boost/interprocess/xsi_shared_memory.hpp>
|
||||
#else
|
||||
#include <boost/interprocess/shared_memory_object.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
// #include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
|
||||
struct OSRMLockFile
|
||||
{
|
||||
boost::filesystem::path operator()()
|
||||
{
|
||||
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
|
||||
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
|
||||
return lock_file;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
class SharedMemory
|
||||
{
|
||||
|
||||
// Remove shared memory on destruction
|
||||
class shm_remove
|
||||
{
|
||||
private:
|
||||
int m_shmid;
|
||||
bool m_initialized;
|
||||
|
||||
public:
|
||||
void SetID(int shmid)
|
||||
{
|
||||
m_shmid = shmid;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
|
||||
shm_remove(const shm_remove &) = delete;
|
||||
~shm_remove()
|
||||
{
|
||||
if (m_initialized)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
|
||||
if (!boost::interprocess::xsi_shared_memory::remove(m_shmid))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void *Ptr() const { return region.get_address(); }
|
||||
|
||||
SharedMemory() = delete;
|
||||
SharedMemory(const SharedMemory &) = delete;
|
||||
|
||||
template <typename IdentifierT>
|
||||
SharedMemory(const boost::filesystem::path &lock_file,
|
||||
const IdentifierT id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true)
|
||||
: key(lock_file.string().c_str(), id)
|
||||
{
|
||||
if (0 == size)
|
||||
{ // read_only
|
||||
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
|
||||
|
||||
region = boost::interprocess::mapped_region(
|
||||
shm,
|
||||
(read_write ? boost::interprocess::read_write : boost::interprocess::read_only));
|
||||
}
|
||||
else
|
||||
{ // writeable pointer
|
||||
// remove previously allocated mem
|
||||
if (remove_prev)
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_or_create, key,
|
||||
size);
|
||||
#ifdef __linux__
|
||||
if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, nullptr))
|
||||
{
|
||||
if (ENOMEM == errno)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
|
||||
|
||||
remover.SetID(shm.get_shmid());
|
||||
SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IdentifierT> static bool RegionExists(const IdentifierT id)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
|
||||
result = RegionExists(key);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename IdentifierT> static bool Remove(const IdentifierT id)
|
||||
{
|
||||
OSRMLockFile lock_file;
|
||||
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
|
||||
return Remove(key);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool RegionExists(const boost::interprocess::xsi_key &key)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(const boost::interprocess::xsi_key &key)
|
||||
{
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
|
||||
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
|
||||
ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
|
||||
}
|
||||
catch (const boost::interprocess::interprocess_exception &e)
|
||||
{
|
||||
if (e.get_error_code() != boost::interprocess::not_found_error)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
boost::interprocess::xsi_key key;
|
||||
boost::interprocess::xsi_shared_memory shm;
|
||||
boost::interprocess::mapped_region region;
|
||||
shm_remove remover;
|
||||
};
|
||||
#else
|
||||
// Windows - specific code
|
||||
class SharedMemory
|
||||
{
|
||||
SharedMemory(const SharedMemory &) = delete;
|
||||
// Remove shared memory on destruction
|
||||
class shm_remove
|
||||
{
|
||||
private:
|
||||
shm_remove(const shm_remove &) = delete;
|
||||
char *m_shmid;
|
||||
bool m_initialized;
|
||||
|
||||
public:
|
||||
void SetID(char *shmid)
|
||||
{
|
||||
m_shmid = shmid;
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
shm_remove() : m_shmid("undefined"), m_initialized(false) {}
|
||||
|
||||
~shm_remove()
|
||||
{
|
||||
if (m_initialized)
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
|
||||
if (!boost::interprocess::shared_memory_object::remove(m_shmid))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void *Ptr() const { return region.get_address(); }
|
||||
|
||||
SharedMemory(const boost::filesystem::path &lock_file,
|
||||
const int id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true)
|
||||
{
|
||||
sprintf(key, "%s.%d", "osrm.lock", id);
|
||||
if (0 == size)
|
||||
{ // read_only
|
||||
shm = boost::interprocess::shared_memory_object(
|
||||
boost::interprocess::open_only, key,
|
||||
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
||||
region = boost::interprocess::mapped_region(
|
||||
shm, read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
||||
}
|
||||
else
|
||||
{ // writeable pointer
|
||||
// remove previously allocated mem
|
||||
if (remove_prev)
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
shm = boost::interprocess::shared_memory_object(boost::interprocess::open_or_create,
|
||||
key, boost::interprocess::read_write);
|
||||
shm.truncate(size);
|
||||
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
|
||||
|
||||
remover.SetID(key);
|
||||
SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size << " bytes";
|
||||
}
|
||||
}
|
||||
|
||||
static bool RegionExists(const int id)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
char k[500];
|
||||
build_key(id, k);
|
||||
result = RegionExists(k);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(const int id)
|
||||
{
|
||||
char k[500];
|
||||
build_key(id, k);
|
||||
return Remove(k);
|
||||
}
|
||||
|
||||
private:
|
||||
static void build_key(int id, char *key) { sprintf(key, "%s.%d", "osrm.lock", id); }
|
||||
|
||||
static bool RegionExists(const char *key)
|
||||
{
|
||||
bool result = true;
|
||||
try
|
||||
{
|
||||
boost::interprocess::shared_memory_object shm(boost::interprocess::open_only, key,
|
||||
boost::interprocess::read_write);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool Remove(char *key)
|
||||
{
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
|
||||
ret = boost::interprocess::shared_memory_object::remove(key);
|
||||
}
|
||||
catch (const boost::interprocess::interprocess_exception &e)
|
||||
{
|
||||
if (e.get_error_code() != boost::interprocess::not_found_error)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char key[500];
|
||||
boost::interprocess::shared_memory_object shm;
|
||||
boost::interprocess::mapped_region region;
|
||||
shm_remove remover;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class LockFileT = OSRMLockFile> class SharedMemoryFactory_tmpl
|
||||
{
|
||||
public:
|
||||
template <typename IdentifierT>
|
||||
static SharedMemory *Get(const IdentifierT &id,
|
||||
const uint64_t size = 0,
|
||||
bool read_write = false,
|
||||
bool remove_prev = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
LockFileT lock_file;
|
||||
if (!boost::filesystem::exists(lock_file()))
|
||||
{
|
||||
if (0 == size)
|
||||
{
|
||||
throw osrm::exception("lock file does not exist, exiting");
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::filesystem::ofstream ofs(lock_file());
|
||||
ofs.close();
|
||||
}
|
||||
}
|
||||
return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
|
||||
}
|
||||
catch (const boost::interprocess::interprocess_exception &e)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
|
||||
<< e.get_error_code();
|
||||
throw osrm::exception(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
SharedMemoryFactory_tmpl() = delete;
|
||||
SharedMemoryFactory_tmpl(const SharedMemoryFactory_tmpl &) = delete;
|
||||
};
|
||||
|
||||
using SharedMemoryFactory = SharedMemoryFactory_tmpl<>;
|
||||
|
||||
#endif // SHARED_MEMORY_FACTORY_HPP
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DATAFACADE_BASE_HPP
|
||||
#define DATAFACADE_BASE_HPP
|
||||
|
||||
// Exposes all data access interfaces to the algorithms via base class ptr
|
||||
|
||||
#include "../../data_structures/edge_based_node.hpp"
|
||||
#include "../../data_structures/external_memory_node.hpp"
|
||||
#include "../../data_structures/phantom_node.hpp"
|
||||
#include "../../data_structures/turn_instructions.hpp"
|
||||
#include "../../util/integer_range.hpp"
|
||||
#include "../../util/osrm_exception.hpp"
|
||||
#include "../../util/string_util.hpp"
|
||||
#include "../../typedefs.h"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
using EdgeRange = osrm::range<EdgeID>;
|
||||
|
||||
template <class EdgeDataT> class BaseDataFacade
|
||||
{
|
||||
public:
|
||||
using RTreeLeaf = EdgeBasedNode;
|
||||
using EdgeData = EdgeDataT;
|
||||
BaseDataFacade() {}
|
||||
virtual ~BaseDataFacade() {}
|
||||
|
||||
// search graph access
|
||||
virtual unsigned GetNumberOfNodes() const = 0;
|
||||
|
||||
virtual unsigned GetNumberOfEdges() const = 0;
|
||||
|
||||
virtual unsigned GetOutDegree(const NodeID n) const = 0;
|
||||
|
||||
virtual NodeID GetTarget(const EdgeID e) const = 0;
|
||||
|
||||
virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
|
||||
|
||||
virtual EdgeID BeginEdges(const NodeID n) const = 0;
|
||||
|
||||
virtual EdgeID EndEdges(const NodeID n) const = 0;
|
||||
|
||||
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
|
||||
|
||||
// searches for a specific edge
|
||||
virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
|
||||
|
||||
virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
|
||||
|
||||
virtual EdgeID
|
||||
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
|
||||
|
||||
// node and edge information access
|
||||
virtual FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const = 0;
|
||||
|
||||
virtual bool EdgeIsCompressed(const unsigned id) const = 0;
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id,
|
||||
std::vector<unsigned> &result_nodes) const = 0;
|
||||
|
||||
virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) = 0;
|
||||
|
||||
virtual std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) = 0;
|
||||
|
||||
virtual std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) = 0;
|
||||
|
||||
virtual unsigned GetCheckSum() const = 0;
|
||||
|
||||
virtual bool IsCoreNode(const NodeID id) const = 0;
|
||||
|
||||
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
|
||||
|
||||
virtual std::string get_name_for_id(const unsigned name_id) const = 0;
|
||||
|
||||
virtual std::size_t GetCoreSize() const = 0;
|
||||
|
||||
virtual std::string GetTimestamp() const = 0;
|
||||
};
|
||||
|
||||
#endif // DATAFACADE_BASE_HPP
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_DATAFACADE_HPP
|
||||
#define INTERNAL_DATAFACADE_HPP
|
||||
|
||||
// implements all data storage when shared memory is _NOT_ used
|
||||
|
||||
#include "datafacade_base.hpp"
|
||||
|
||||
#include "../../algorithms/geospatial_query.hpp"
|
||||
#include "../../data_structures/original_edge_data.hpp"
|
||||
#include "../../data_structures/query_node.hpp"
|
||||
#include "../../data_structures/query_edge.hpp"
|
||||
#include "../../data_structures/shared_memory_vector_wrapper.hpp"
|
||||
#include "../../data_structures/static_graph.hpp"
|
||||
#include "../../data_structures/static_rtree.hpp"
|
||||
#include "../../data_structures/range_table.hpp"
|
||||
#include "../../util/graph_loader.hpp"
|
||||
#include "../../util/simple_logger.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
template <class EdgeDataT> class InternalDataFacade final : public BaseDataFacade<EdgeDataT>
|
||||
{
|
||||
|
||||
private:
|
||||
using super = BaseDataFacade<EdgeDataT>;
|
||||
using QueryGraph = StaticGraph<typename super::EdgeData>;
|
||||
using InputEdge = typename QueryGraph::InputEdge;
|
||||
using RTreeLeaf = typename super::RTreeLeaf;
|
||||
using InternalRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>;
|
||||
using InternalGeospatialQuery = GeospatialQuery<InternalRTree>;
|
||||
|
||||
InternalDataFacade() {}
|
||||
|
||||
unsigned m_check_sum;
|
||||
unsigned m_number_of_nodes;
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
std::string m_timestamp;
|
||||
|
||||
std::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
|
||||
ShM<NodeID, false>::vector m_via_node_list;
|
||||
ShM<unsigned, false>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
|
||||
ShM<TravelMode, false>::vector m_travel_mode_list;
|
||||
ShM<char, false>::vector m_names_char_list;
|
||||
ShM<bool, false>::vector m_edge_is_compressed;
|
||||
ShM<unsigned, false>::vector m_geometry_indices;
|
||||
ShM<unsigned, false>::vector m_geometry_list;
|
||||
ShM<bool, false>::vector m_is_core_node;
|
||||
|
||||
boost::thread_specific_ptr<InternalRTree> m_static_rtree;
|
||||
boost::thread_specific_ptr<InternalGeospatialQuery> m_geospatial_query;
|
||||
boost::filesystem::path ram_index_path;
|
||||
boost::filesystem::path file_index_path;
|
||||
RangeTable<16, false> m_name_table;
|
||||
|
||||
void LoadTimestamp(const boost::filesystem::path ×tamp_path)
|
||||
{
|
||||
if (boost::filesystem::exists(timestamp_path))
|
||||
{
|
||||
SimpleLogger().Write() << "Loading Timestamp";
|
||||
boost::filesystem::ifstream timestamp_stream(timestamp_path);
|
||||
if (!timestamp_stream)
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
|
||||
}
|
||||
getline(timestamp_stream, m_timestamp);
|
||||
timestamp_stream.close();
|
||||
}
|
||||
if (m_timestamp.empty())
|
||||
{
|
||||
m_timestamp = "n/a";
|
||||
}
|
||||
if (25 < m_timestamp.length())
|
||||
{
|
||||
m_timestamp.resize(25);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGraph(const boost::filesystem::path &hsgr_path)
|
||||
{
|
||||
typename ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
|
||||
typename ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
|
||||
|
||||
SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
|
||||
|
||||
m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
|
||||
|
||||
BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
|
||||
// BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
|
||||
SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
|
||||
<< " edges";
|
||||
m_query_graph = std::unique_ptr<QueryGraph>(new QueryGraph(node_list, edge_list));
|
||||
|
||||
BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
|
||||
BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
|
||||
SimpleLogger().Write() << "Data checksum is " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
|
||||
const boost::filesystem::path &edges_file)
|
||||
{
|
||||
boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
|
||||
|
||||
QueryNode current_node;
|
||||
unsigned number_of_coordinates = 0;
|
||||
nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
|
||||
m_coordinate_list =
|
||||
std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
|
||||
for (unsigned i = 0; i < number_of_coordinates; ++i)
|
||||
{
|
||||
nodes_input_stream.read((char *)¤t_node, sizeof(QueryNode));
|
||||
m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
|
||||
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
|
||||
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
|
||||
}
|
||||
nodes_input_stream.close();
|
||||
|
||||
boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
|
||||
unsigned number_of_edges = 0;
|
||||
edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
|
||||
m_via_node_list.resize(number_of_edges);
|
||||
m_name_ID_list.resize(number_of_edges);
|
||||
m_turn_instruction_list.resize(number_of_edges);
|
||||
m_travel_mode_list.resize(number_of_edges);
|
||||
m_edge_is_compressed.resize(number_of_edges);
|
||||
|
||||
unsigned compressed = 0;
|
||||
|
||||
OriginalEdgeData current_edge_data;
|
||||
for (unsigned i = 0; i < number_of_edges; ++i)
|
||||
{
|
||||
edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
|
||||
m_via_node_list[i] = current_edge_data.via_node;
|
||||
m_name_ID_list[i] = current_edge_data.name_id;
|
||||
m_turn_instruction_list[i] = current_edge_data.turn_instruction;
|
||||
m_travel_mode_list[i] = current_edge_data.travel_mode;
|
||||
m_edge_is_compressed[i] = current_edge_data.compressed_geometry;
|
||||
if (m_edge_is_compressed[i])
|
||||
{
|
||||
++compressed;
|
||||
}
|
||||
}
|
||||
|
||||
edges_input_stream.close();
|
||||
}
|
||||
|
||||
void LoadCoreInformation(const boost::filesystem::path &core_data_file)
|
||||
{
|
||||
std::ifstream core_stream(core_data_file.string().c_str(), std::ios::binary);
|
||||
unsigned number_of_markers;
|
||||
core_stream.read((char *)&number_of_markers, sizeof(unsigned));
|
||||
|
||||
std::vector<char> unpacked_core_markers(number_of_markers);
|
||||
core_stream.read((char *)unpacked_core_markers.data(), sizeof(char) * number_of_markers);
|
||||
|
||||
// in this case we have nothing to do
|
||||
if (number_of_markers <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_is_core_node.resize(number_of_markers);
|
||||
for (auto i = 0u; i < number_of_markers; ++i)
|
||||
{
|
||||
BOOST_ASSERT(unpacked_core_markers[i] == 0 || unpacked_core_markers[i] == 1);
|
||||
m_is_core_node[i] = unpacked_core_markers[i] == 1;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadGeometries(const boost::filesystem::path &geometry_file)
|
||||
{
|
||||
std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
|
||||
unsigned number_of_indices = 0;
|
||||
unsigned number_of_compressed_geometries = 0;
|
||||
|
||||
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
|
||||
|
||||
m_geometry_indices.resize(number_of_indices);
|
||||
if (number_of_indices > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_indices[0]),
|
||||
number_of_indices * sizeof(unsigned));
|
||||
}
|
||||
|
||||
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
|
||||
|
||||
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
|
||||
m_geometry_list.resize(number_of_compressed_geometries);
|
||||
|
||||
if (number_of_compressed_geometries > 0)
|
||||
{
|
||||
geometry_stream.read((char *)&(m_geometry_list[0]),
|
||||
number_of_compressed_geometries * sizeof(unsigned));
|
||||
}
|
||||
geometry_stream.close();
|
||||
}
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
m_static_rtree.reset(new InternalRTree(ram_index_path, file_index_path, m_coordinate_list));
|
||||
m_geospatial_query.reset(new InternalGeospatialQuery(*m_static_rtree, m_coordinate_list));
|
||||
}
|
||||
|
||||
void LoadStreetNames(const boost::filesystem::path &names_file)
|
||||
{
|
||||
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
|
||||
|
||||
name_stream >> m_name_table;
|
||||
|
||||
unsigned number_of_chars = 0;
|
||||
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
|
||||
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
|
||||
name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
|
||||
if (0 == m_names_char_list.size())
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "list of street names is empty";
|
||||
}
|
||||
name_stream.close();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~InternalDataFacade()
|
||||
{
|
||||
m_static_rtree.reset();
|
||||
m_geospatial_query.reset();
|
||||
}
|
||||
|
||||
explicit InternalDataFacade(const std::unordered_map<std::string, boost::filesystem::path> &server_paths)
|
||||
{
|
||||
// cache end iterator to quickly check .find against
|
||||
const auto end_it = end(server_paths);
|
||||
|
||||
const auto file_for = [&server_paths, &end_it](const std::string &path)
|
||||
{
|
||||
const auto it = server_paths.find(path);
|
||||
if (it == end_it || !boost::filesystem::is_regular_file(it->second))
|
||||
throw osrm::exception("no valid " + path + " file given in ini file");
|
||||
return it->second;
|
||||
};
|
||||
|
||||
ram_index_path = file_for("ramindex");
|
||||
file_index_path = file_for("fileindex");
|
||||
|
||||
SimpleLogger().Write() << "loading graph data";
|
||||
LoadGraph(file_for("hsgrdata"));
|
||||
|
||||
SimpleLogger().Write() << "loading edge information";
|
||||
LoadNodeAndEdgeInformation(file_for("nodesdata"), file_for("edgesdata"));
|
||||
|
||||
SimpleLogger().Write() << "loading core information";
|
||||
LoadCoreInformation(file_for("coredata"));
|
||||
|
||||
SimpleLogger().Write() << "loading geometries";
|
||||
LoadGeometries(file_for("geometries"));
|
||||
|
||||
SimpleLogger().Write() << "loading timestamp";
|
||||
LoadTimestamp(file_for("timestamp"));
|
||||
|
||||
SimpleLogger().Write() << "loading street names";
|
||||
LoadStreetNames(file_for("namesdata"));
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const override final
|
||||
{
|
||||
return m_query_graph->GetOutDegree(n);
|
||||
}
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeID e) const override final
|
||||
{
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
};
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const override final
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID
|
||||
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const override final
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
bool EdgeIsCompressed(const unsigned id) const override final
|
||||
{
|
||||
return m_edge_is_compressed.at(id);
|
||||
}
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_travel_mode_list.at(id);
|
||||
}
|
||||
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) override final
|
||||
{
|
||||
if (!m_static_rtree.get())
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range);
|
||||
}
|
||||
|
||||
|
||||
unsigned GetCheckSum() const override final { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
}
|
||||
|
||||
std::string get_name_for_id(const unsigned name_id) const override final
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() == name_id)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
auto range = m_name_table.GetRange(name_id);
|
||||
|
||||
std::string result;
|
||||
result.reserve(range.size());
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1, result.begin());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
virtual std::size_t GetCoreSize() const override final
|
||||
{
|
||||
return m_is_core_node.size();
|
||||
}
|
||||
|
||||
virtual bool IsCoreNode(const NodeID id) const override final
|
||||
{
|
||||
if (m_is_core_node.size() > 0)
|
||||
{
|
||||
return m_is_core_node[id];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id,
|
||||
std::vector<unsigned> &result_nodes) const override final
|
||||
{
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
result_nodes.clear();
|
||||
result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
|
||||
m_geometry_list.begin() + end);
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const override final { return m_timestamp; }
|
||||
};
|
||||
|
||||
#endif // INTERNAL_DATAFACADE_HPP
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_BARRIERS_HPP
|
||||
#define SHARED_BARRIERS_HPP
|
||||
|
||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||
#include <boost/interprocess/sync/named_condition.hpp>
|
||||
|
||||
struct SharedBarriers
|
||||
{
|
||||
|
||||
SharedBarriers()
|
||||
: pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
|
||||
update_mutex(boost::interprocess::open_or_create, "update"),
|
||||
query_mutex(boost::interprocess::open_or_create, "query"),
|
||||
no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
|
||||
update_ongoing(false), number_of_queries(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Mutex to protect access to the boolean variable
|
||||
boost::interprocess::named_mutex pending_update_mutex;
|
||||
boost::interprocess::named_mutex update_mutex;
|
||||
boost::interprocess::named_mutex query_mutex;
|
||||
|
||||
// Condition that no update is running
|
||||
boost::interprocess::named_condition no_running_queries_condition;
|
||||
|
||||
// Is there an ongoing update?
|
||||
bool update_ongoing;
|
||||
// Is there any query?
|
||||
int number_of_queries;
|
||||
};
|
||||
|
||||
#endif // SHARED_BARRIERS_HPP
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_DATAFACADE_HPP
|
||||
#define SHARED_DATAFACADE_HPP
|
||||
|
||||
// implements all data storage when shared memory _IS_ used
|
||||
|
||||
#include "datafacade_base.hpp"
|
||||
#include "shared_datatype.hpp"
|
||||
|
||||
#include "../../algorithms/geospatial_query.hpp"
|
||||
#include "../../data_structures/range_table.hpp"
|
||||
#include "../../data_structures/static_graph.hpp"
|
||||
#include "../../data_structures/static_rtree.hpp"
|
||||
#include "../../util/make_unique.hpp"
|
||||
#include "../../util/simple_logger.hpp"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
template <class EdgeDataT> class SharedDataFacade final : public BaseDataFacade<EdgeDataT>
|
||||
{
|
||||
|
||||
private:
|
||||
using EdgeData = EdgeDataT;
|
||||
using super = BaseDataFacade<EdgeData>;
|
||||
using QueryGraph = StaticGraph<EdgeData, true>;
|
||||
using GraphNode = typename StaticGraph<EdgeData, true>::NodeArrayEntry;
|
||||
using GraphEdge = typename StaticGraph<EdgeData, true>::EdgeArrayEntry;
|
||||
using NameIndexBlock = typename RangeTable<16, true>::BlockT;
|
||||
using InputEdge = typename QueryGraph::InputEdge;
|
||||
using RTreeLeaf = typename super::RTreeLeaf;
|
||||
using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
|
||||
using SharedGeospatialQuery = GeospatialQuery<SharedRTree>;
|
||||
using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
|
||||
using RTreeNode = typename SharedRTree::TreeNode;
|
||||
|
||||
SharedDataLayout *data_layout;
|
||||
char *shared_memory;
|
||||
SharedDataTimestamp *data_timestamp_ptr;
|
||||
|
||||
SharedDataType CURRENT_LAYOUT;
|
||||
SharedDataType CURRENT_DATA;
|
||||
unsigned CURRENT_TIMESTAMP;
|
||||
|
||||
unsigned m_check_sum;
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
std::unique_ptr<SharedMemory> m_layout_memory;
|
||||
std::unique_ptr<SharedMemory> m_large_memory;
|
||||
std::string m_timestamp;
|
||||
|
||||
std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
|
||||
ShM<NodeID, true>::vector m_via_node_list;
|
||||
ShM<unsigned, true>::vector m_name_ID_list;
|
||||
ShM<TurnInstruction, true>::vector m_turn_instruction_list;
|
||||
ShM<TravelMode, true>::vector m_travel_mode_list;
|
||||
ShM<char, true>::vector m_names_char_list;
|
||||
ShM<unsigned, true>::vector m_name_begin_indices;
|
||||
ShM<bool, true>::vector m_edge_is_compressed;
|
||||
ShM<unsigned, true>::vector m_geometry_indices;
|
||||
ShM<unsigned, true>::vector m_geometry_list;
|
||||
ShM<bool, true>::vector m_is_core_node;
|
||||
|
||||
boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
|
||||
boost::thread_specific_ptr<SharedGeospatialQuery> m_geospatial_query;
|
||||
boost::filesystem::path file_index_path;
|
||||
|
||||
std::shared_ptr<RangeTable<16, true>> m_name_table;
|
||||
|
||||
void LoadChecksum()
|
||||
{
|
||||
m_check_sum =
|
||||
*data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
|
||||
SimpleLogger().Write() << "set checksum: " << m_check_sum;
|
||||
}
|
||||
|
||||
void LoadTimestamp()
|
||||
{
|
||||
char *timestamp_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
|
||||
m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
|
||||
std::copy(timestamp_ptr,
|
||||
timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
|
||||
m_timestamp.begin());
|
||||
}
|
||||
|
||||
void LoadRTree()
|
||||
{
|
||||
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
|
||||
|
||||
RTreeNode *tree_ptr =
|
||||
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
|
||||
m_static_rtree.reset(new TimeStampedRTreePair(
|
||||
CURRENT_TIMESTAMP,
|
||||
osrm::make_unique<SharedRTree>(
|
||||
tree_ptr, data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
|
||||
file_index_path, m_coordinate_list)));
|
||||
m_geospatial_query.reset(new SharedGeospatialQuery(*m_static_rtree->second, m_coordinate_list));
|
||||
}
|
||||
|
||||
void LoadGraph()
|
||||
{
|
||||
GraphNode *graph_nodes_ptr =
|
||||
data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
|
||||
|
||||
GraphEdge *graph_edges_ptr =
|
||||
data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
|
||||
|
||||
typename ShM<GraphNode, true>::vector node_list(
|
||||
graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
|
||||
typename ShM<GraphEdge, true>::vector edge_list(
|
||||
graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
|
||||
m_query_graph.reset(new QueryGraph(node_list, edge_list));
|
||||
}
|
||||
|
||||
void LoadNodeAndEdgeInformation()
|
||||
{
|
||||
|
||||
FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
|
||||
shared_memory, SharedDataLayout::COORDINATE_LIST);
|
||||
m_coordinate_list = osrm::make_unique<ShM<FixedPointCoordinate, true>::vector>(
|
||||
coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
|
||||
|
||||
TravelMode *travel_mode_list_ptr =
|
||||
data_layout->GetBlockPtr<TravelMode>(shared_memory, SharedDataLayout::TRAVEL_MODE);
|
||||
typename ShM<TravelMode, true>::vector travel_mode_list(
|
||||
travel_mode_list_ptr, data_layout->num_entries[SharedDataLayout::TRAVEL_MODE]);
|
||||
m_travel_mode_list.swap(travel_mode_list);
|
||||
|
||||
TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
|
||||
shared_memory, SharedDataLayout::TURN_INSTRUCTION);
|
||||
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
|
||||
turn_instruction_list_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
|
||||
m_turn_instruction_list.swap(turn_instruction_list);
|
||||
|
||||
unsigned *name_id_list_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
|
||||
typename ShM<unsigned, true>::vector name_id_list(
|
||||
name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
|
||||
m_name_ID_list.swap(name_id_list);
|
||||
}
|
||||
|
||||
void LoadViaNodeList()
|
||||
{
|
||||
NodeID *via_node_list_ptr =
|
||||
data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
|
||||
typename ShM<NodeID, true>::vector via_node_list(
|
||||
via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
|
||||
m_via_node_list.swap(via_node_list);
|
||||
}
|
||||
|
||||
void LoadNames()
|
||||
{
|
||||
unsigned *offsets_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
|
||||
NameIndexBlock *blocks_ptr =
|
||||
data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
|
||||
typename ShM<unsigned, true>::vector name_offsets(
|
||||
offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
|
||||
typename ShM<NameIndexBlock, true>::vector name_blocks(
|
||||
blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
|
||||
|
||||
char *names_list_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
|
||||
typename ShM<char, true>::vector names_char_list(
|
||||
names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
|
||||
m_name_table = osrm::make_unique<RangeTable<16, true>>(
|
||||
name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
|
||||
|
||||
m_names_char_list.swap(names_char_list);
|
||||
}
|
||||
|
||||
void LoadCoreInformation()
|
||||
{
|
||||
if (data_layout->num_entries[SharedDataLayout::CORE_MARKER] <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned *core_marker_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, SharedDataLayout::CORE_MARKER);
|
||||
typename ShM<bool, true>::vector is_core_node(
|
||||
core_marker_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::CORE_MARKER]);
|
||||
m_is_core_node.swap(is_core_node);
|
||||
}
|
||||
|
||||
void LoadGeometries()
|
||||
{
|
||||
unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
|
||||
shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
|
||||
typename ShM<bool, true>::vector edge_is_compressed(
|
||||
geometries_compressed_ptr,
|
||||
data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
|
||||
m_edge_is_compressed.swap(edge_is_compressed);
|
||||
|
||||
unsigned *geometries_index_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
|
||||
typename ShM<unsigned, true>::vector geometry_begin_indices(
|
||||
geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
|
||||
m_geometry_indices.swap(geometry_begin_indices);
|
||||
|
||||
unsigned *geometries_list_ptr =
|
||||
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
|
||||
typename ShM<unsigned, true>::vector geometry_list(
|
||||
geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
|
||||
m_geometry_list.swap(geometry_list);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~SharedDataFacade() {}
|
||||
|
||||
SharedDataFacade()
|
||||
{
|
||||
data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
|
||||
CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)->Ptr();
|
||||
CURRENT_LAYOUT = LAYOUT_NONE;
|
||||
CURRENT_DATA = DATA_NONE;
|
||||
CURRENT_TIMESTAMP = 0;
|
||||
|
||||
// load data
|
||||
CheckAndReloadFacade();
|
||||
}
|
||||
|
||||
void CheckAndReloadFacade()
|
||||
{
|
||||
if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
|
||||
CURRENT_DATA != data_timestamp_ptr->data ||
|
||||
CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
|
||||
{
|
||||
// release the previous shared memory segments
|
||||
SharedMemory::Remove(CURRENT_LAYOUT);
|
||||
SharedMemory::Remove(CURRENT_DATA);
|
||||
|
||||
CURRENT_LAYOUT = data_timestamp_ptr->layout;
|
||||
CURRENT_DATA = data_timestamp_ptr->data;
|
||||
CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
|
||||
|
||||
m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
|
||||
|
||||
data_layout = (SharedDataLayout *)(m_layout_memory->Ptr());
|
||||
|
||||
m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
|
||||
shared_memory = (char *)(m_large_memory->Ptr());
|
||||
|
||||
const char *file_index_ptr =
|
||||
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
|
||||
file_index_path = boost::filesystem::path(file_index_ptr);
|
||||
if (!boost::filesystem::exists(file_index_path))
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
|
||||
throw osrm::exception("Could not load leaf index file. "
|
||||
"Is any data loaded into shared memory?");
|
||||
}
|
||||
|
||||
LoadGraph();
|
||||
LoadChecksum();
|
||||
LoadNodeAndEdgeInformation();
|
||||
LoadGeometries();
|
||||
LoadTimestamp();
|
||||
LoadViaNodeList();
|
||||
LoadNames();
|
||||
LoadCoreInformation();
|
||||
|
||||
data_layout->PrintInformation();
|
||||
|
||||
SimpleLogger().Write() << "number of geometries: " << m_coordinate_list->size();
|
||||
for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
|
||||
{
|
||||
if (!GetCoordinateOfNode(i).is_valid())
|
||||
{
|
||||
SimpleLogger().Write() << "coordinate " << i << " not valid";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search graph access
|
||||
unsigned GetNumberOfNodes() const override final { return m_query_graph->GetNumberOfNodes(); }
|
||||
|
||||
unsigned GetNumberOfEdges() const override final { return m_query_graph->GetNumberOfEdges(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeID n) const override final
|
||||
{
|
||||
return m_query_graph->GetOutDegree(n);
|
||||
}
|
||||
|
||||
NodeID GetTarget(const EdgeID e) const override final { return m_query_graph->GetTarget(e); }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeID e) const override final
|
||||
{
|
||||
return m_query_graph->GetEdgeData(e);
|
||||
}
|
||||
|
||||
EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph->BeginEdges(n); }
|
||||
|
||||
EdgeID EndEdges(const NodeID n) const override final { return m_query_graph->EndEdges(n); }
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
|
||||
{
|
||||
return m_query_graph->GetAdjacentEdgeRange(node);
|
||||
};
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeID FindEdge(const NodeID from, const NodeID to) const override final
|
||||
{
|
||||
return m_query_graph->FindEdge(from, to);
|
||||
}
|
||||
|
||||
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
|
||||
{
|
||||
return m_query_graph->FindEdgeInEitherDirection(from, to);
|
||||
}
|
||||
|
||||
EdgeID
|
||||
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
|
||||
{
|
||||
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
|
||||
}
|
||||
|
||||
// node and edge information access
|
||||
FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const override final
|
||||
{
|
||||
return m_coordinate_list->at(id);
|
||||
};
|
||||
|
||||
virtual bool EdgeIsCompressed(const unsigned id) const override final
|
||||
{
|
||||
return m_edge_is_compressed.at(id);
|
||||
}
|
||||
|
||||
virtual void GetUncompressedGeometry(const unsigned id,
|
||||
std::vector<unsigned> &result_nodes) const override final
|
||||
{
|
||||
const unsigned begin = m_geometry_indices.at(id);
|
||||
const unsigned end = m_geometry_indices.at(id + 1);
|
||||
|
||||
result_nodes.clear();
|
||||
result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
|
||||
m_geometry_list.begin() + end);
|
||||
}
|
||||
|
||||
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_via_node_list.at(id);
|
||||
}
|
||||
|
||||
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_turn_instruction_list.at(id);
|
||||
}
|
||||
|
||||
TravelMode GetTravelModeForEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_travel_mode_list.at(id);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodesInRange(input_coordinate, max_distance, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, bearing, bearing_range);
|
||||
}
|
||||
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180) override final
|
||||
{
|
||||
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
|
||||
{
|
||||
LoadRTree();
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
}
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(input_coordinate, bearing, bearing_range);
|
||||
}
|
||||
|
||||
unsigned GetCheckSum() const override final { return m_check_sum; }
|
||||
|
||||
unsigned GetNameIndexFromEdgeID(const unsigned id) const override final
|
||||
{
|
||||
return m_name_ID_list.at(id);
|
||||
};
|
||||
|
||||
std::string get_name_for_id(const unsigned name_id) const override final
|
||||
{
|
||||
if (std::numeric_limits<unsigned>::max() == name_id)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
auto range = m_name_table->GetRange(name_id);
|
||||
|
||||
std::string result;
|
||||
result.reserve(range.size());
|
||||
if (range.begin() != range.end())
|
||||
{
|
||||
result.resize(range.back() - range.front() + 1);
|
||||
std::copy(m_names_char_list.begin() + range.front(),
|
||||
m_names_char_list.begin() + range.back() + 1, result.begin());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsCoreNode(const NodeID id) const override final
|
||||
{
|
||||
if (m_is_core_node.size() > 0)
|
||||
{
|
||||
return m_is_core_node.at(id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual std::size_t GetCoreSize() const override final
|
||||
{
|
||||
return m_is_core_node.size();
|
||||
}
|
||||
|
||||
std::string GetTimestamp() const override final { return m_timestamp; }
|
||||
};
|
||||
|
||||
#endif // SHARED_DATAFACADE_HPP
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHARED_DATA_TYPE_HPP
|
||||
#define SHARED_DATA_TYPE_HPP
|
||||
|
||||
#include "../../util/osrm_exception.hpp"
|
||||
#include "../../util/simple_logger.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Added at the start and end of each block as sanity check
|
||||
static const char CANARY[] = "OSRM";
|
||||
}
|
||||
|
||||
struct SharedDataLayout
|
||||
{
|
||||
enum BlockID
|
||||
{
|
||||
NAME_OFFSETS = 0,
|
||||
NAME_BLOCKS,
|
||||
NAME_CHAR_LIST,
|
||||
NAME_ID_LIST,
|
||||
VIA_NODE_LIST,
|
||||
GRAPH_NODE_LIST,
|
||||
GRAPH_EDGE_LIST,
|
||||
COORDINATE_LIST,
|
||||
TURN_INSTRUCTION,
|
||||
TRAVEL_MODE,
|
||||
R_SEARCH_TREE,
|
||||
GEOMETRIES_INDEX,
|
||||
GEOMETRIES_LIST,
|
||||
GEOMETRIES_INDICATORS,
|
||||
HSGR_CHECKSUM,
|
||||
TIMESTAMP,
|
||||
FILE_INDEX_PATH,
|
||||
CORE_MARKER,
|
||||
NUM_BLOCKS
|
||||
};
|
||||
|
||||
std::array<uint64_t, NUM_BLOCKS> num_entries;
|
||||
std::array<uint64_t, NUM_BLOCKS> entry_size;
|
||||
|
||||
SharedDataLayout() : num_entries(), entry_size() {}
|
||||
|
||||
void PrintInformation() const
|
||||
{
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS "
|
||||
<< ": " << GetBlockSize(NAME_OFFSETS);
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS "
|
||||
<< ": " << GetBlockSize(NAME_BLOCKS);
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST "
|
||||
<< ": " << GetBlockSize(NAME_CHAR_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST "
|
||||
<< ": " << GetBlockSize(NAME_ID_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST "
|
||||
<< ": " << GetBlockSize(VIA_NODE_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST "
|
||||
<< ": " << GetBlockSize(GRAPH_NODE_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST "
|
||||
<< ": " << GetBlockSize(GRAPH_EDGE_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST "
|
||||
<< ": " << GetBlockSize(COORDINATE_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION "
|
||||
<< ": " << GetBlockSize(TURN_INSTRUCTION);
|
||||
SimpleLogger().Write(logDEBUG) << "TRAVEL_MODE "
|
||||
<< ": " << GetBlockSize(TRAVEL_MODE);
|
||||
SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE "
|
||||
<< ": " << GetBlockSize(R_SEARCH_TREE);
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX "
|
||||
<< ": " << GetBlockSize(GEOMETRIES_INDEX);
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST "
|
||||
<< ": " << GetBlockSize(GEOMETRIES_LIST);
|
||||
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS"
|
||||
<< ": " << GetBlockSize(GEOMETRIES_INDICATORS);
|
||||
SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM "
|
||||
<< ": " << GetBlockSize(HSGR_CHECKSUM);
|
||||
SimpleLogger().Write(logDEBUG) << "TIMESTAMP "
|
||||
<< ": " << GetBlockSize(TIMESTAMP);
|
||||
SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH "
|
||||
<< ": " << GetBlockSize(FILE_INDEX_PATH);
|
||||
SimpleLogger().Write(logDEBUG) << "CORE_MARKER "
|
||||
<< ": " << GetBlockSize(CORE_MARKER);
|
||||
}
|
||||
|
||||
template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
|
||||
{
|
||||
num_entries[bid] = entries;
|
||||
entry_size[bid] = sizeof(T);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockSize(BlockID bid) const
|
||||
{
|
||||
// special bit encoding
|
||||
if (bid == GEOMETRIES_INDICATORS || bid == CORE_MARKER)
|
||||
{
|
||||
return (num_entries[bid] / 32 + 1) *
|
||||
entry_size[bid];
|
||||
}
|
||||
|
||||
return num_entries[bid] * entry_size[bid];
|
||||
}
|
||||
|
||||
inline uint64_t GetSizeOfLayout() const
|
||||
{
|
||||
return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
|
||||
}
|
||||
|
||||
inline uint64_t GetBlockOffset(BlockID bid) const
|
||||
{
|
||||
uint64_t result = sizeof(CANARY);
|
||||
for (auto i = 0; i < bid; i++)
|
||||
{
|
||||
result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, bool WRITE_CANARY = false>
|
||||
inline T *GetBlockPtr(char *shared_memory, BlockID bid)
|
||||
{
|
||||
T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
|
||||
if (WRITE_CANARY)
|
||||
{
|
||||
char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
|
||||
char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
|
||||
bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
|
||||
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
|
||||
if (!start_canary_alive)
|
||||
{
|
||||
throw osrm::exception("Start canary of block corrupted.");
|
||||
}
|
||||
if (!end_canary_alive)
|
||||
{
|
||||
throw osrm::exception("End canary of block corrupted.");
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
enum SharedDataType
|
||||
{
|
||||
CURRENT_REGIONS,
|
||||
LAYOUT_1,
|
||||
DATA_1,
|
||||
LAYOUT_2,
|
||||
DATA_2,
|
||||
LAYOUT_NONE,
|
||||
DATA_NONE
|
||||
};
|
||||
|
||||
struct SharedDataTimestamp
|
||||
{
|
||||
SharedDataType layout;
|
||||
SharedDataType data;
|
||||
unsigned timestamp;
|
||||
};
|
||||
|
||||
#endif /* SHARED_DATA_TYPE_HPP */
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DESCRIPTION_FACTORY_HPP
|
||||
#define DESCRIPTION_FACTORY_HPP
|
||||
|
||||
#include "../algorithms/douglas_peucker.hpp"
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
#include "../data_structures/turn_instructions.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
struct PathData;
|
||||
/* This class is fed with all way segments in consecutive order
|
||||
* and produces the description plus the encoded polyline */
|
||||
|
||||
class DescriptionFactory
|
||||
{
|
||||
DouglasPeucker polyline_generalizer;
|
||||
PhantomNode start_phantom, target_phantom;
|
||||
|
||||
double DegreeToRadian(const double degree) const;
|
||||
double RadianToDegree(const double degree) const;
|
||||
|
||||
std::vector<unsigned> via_indices;
|
||||
|
||||
double entire_length;
|
||||
|
||||
public:
|
||||
struct RouteSummary
|
||||
{
|
||||
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) {}
|
||||
|
||||
void BuildDurationAndLengthStrings(const double raw_distance, const unsigned raw_duration)
|
||||
{
|
||||
// compute distance/duration for route summary
|
||||
distance = static_cast<unsigned>(std::round(raw_distance));
|
||||
duration = static_cast<EdgeWeight>(std::round(raw_duration / 10.));
|
||||
}
|
||||
} summary;
|
||||
|
||||
// I know, declaring this public is considered bad. I'm lazy
|
||||
std::vector<SegmentInformation> path_description;
|
||||
DescriptionFactory();
|
||||
void AppendSegment(const FixedPointCoordinate &coordinate, const PathData &data);
|
||||
void BuildRouteSummary(const double distance, const unsigned time);
|
||||
void SetStartSegment(const PhantomNode &start_phantom, const bool traversed_in_reverse);
|
||||
void SetEndSegment(const PhantomNode &start_phantom,
|
||||
const bool traversed_in_reverse,
|
||||
const bool is_via_location = false);
|
||||
osrm::json::Value AppendGeometryString(const bool return_encoded);
|
||||
std::vector<unsigned> const &GetViaIndices() const;
|
||||
|
||||
double get_entire_length() const { return entire_length; }
|
||||
|
||||
void Run(const unsigned zoom_level);
|
||||
};
|
||||
|
||||
#endif /* DESCRIPTION_FACTORY_HPP */
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DESCRIPTOR_BASE_HPP
|
||||
#define DESCRIPTOR_BASE_HPP
|
||||
|
||||
#include "../algorithms/coordinate_calculation.hpp"
|
||||
#include "../data_structures/internal_route_result.hpp"
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct DescriptorTable : public std::unordered_map<std::string, unsigned>
|
||||
{
|
||||
unsigned get_id(const std::string &key)
|
||||
{
|
||||
auto iter = find(key);
|
||||
if (iter != end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct DescriptorConfig
|
||||
{
|
||||
DescriptorConfig() : instructions(true), geometry(true), encode_geometry(true), zoom_level(18)
|
||||
{
|
||||
}
|
||||
|
||||
template <class OtherT>
|
||||
DescriptorConfig(const OtherT &other)
|
||||
: instructions(other.print_instructions), geometry(other.geometry),
|
||||
encode_geometry(other.compression), zoom_level(other.zoom_level)
|
||||
{
|
||||
BOOST_ASSERT(zoom_level >= 0);
|
||||
}
|
||||
|
||||
bool instructions;
|
||||
bool geometry;
|
||||
bool encode_geometry;
|
||||
short zoom_level;
|
||||
};
|
||||
|
||||
template <class DataFacadeT> class BaseDescriptor
|
||||
{
|
||||
public:
|
||||
BaseDescriptor() {}
|
||||
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() {}
|
||||
virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) = 0;
|
||||
virtual void SetConfig(const DescriptorConfig &c) = 0;
|
||||
};
|
||||
|
||||
#endif // DESCRIPTOR_BASE_HPP
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GPX_DESCRIPTOR_HPP
|
||||
#define GPX_DESCRIPTOR_HPP
|
||||
|
||||
#include "descriptor_base.hpp"
|
||||
#include "../util/xml_renderer.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template <class DataFacadeT> class GPXDescriptor final : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DescriptorConfig config;
|
||||
DataFacadeT *facade;
|
||||
|
||||
void AddRoutePoint(const FixedPointCoordinate &coordinate, osrm::json::Array &json_route)
|
||||
{
|
||||
osrm::json::Object json_lat;
|
||||
osrm::json::Object json_lon;
|
||||
osrm::json::Array json_row;
|
||||
|
||||
std::string tmp;
|
||||
|
||||
coordinate_calculation::lat_or_lon_to_string(coordinate.lat, tmp);
|
||||
json_lat.values["_lat"] = tmp;
|
||||
|
||||
coordinate_calculation::lat_or_lon_to_string(coordinate.lon, tmp);
|
||||
json_lon.values["_lon"] = tmp;
|
||||
|
||||
json_row.values.push_back(json_lat);
|
||||
json_row.values.push_back(json_lon);
|
||||
osrm::json::Object entry;
|
||||
entry.values["rtept"] = json_row;
|
||||
json_route.values.push_back(entry);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit GPXDescriptor(DataFacadeT *facade) : facade(facade) {}
|
||||
|
||||
virtual void SetConfig(const DescriptorConfig &c) final { config = c; }
|
||||
|
||||
virtual void Run(const InternalRouteResult &raw_route, osrm::json::Object &json_result) final
|
||||
{
|
||||
osrm::json::Array json_route;
|
||||
if (raw_route.shortest_path_length != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.front().source_phantom.location,
|
||||
json_route);
|
||||
|
||||
for (const std::vector<PathData> &path_data_vector : raw_route.unpacked_path_segments)
|
||||
{
|
||||
for (const PathData &path_data : path_data_vector)
|
||||
{
|
||||
const FixedPointCoordinate current_coordinate =
|
||||
facade->GetCoordinateOfNode(path_data.node);
|
||||
AddRoutePoint(current_coordinate, json_route);
|
||||
}
|
||||
}
|
||||
AddRoutePoint(raw_route.segment_end_coordinates.back().target_phantom.location,
|
||||
json_route);
|
||||
}
|
||||
// osrm::json::gpx_render(reply.content, json_route);
|
||||
json_result.values["route"] = json_route;
|
||||
}
|
||||
};
|
||||
#endif // GPX_DESCRIPTOR_HPP
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef JSON_DESCRIPTOR_HPP
|
||||
#define JSON_DESCRIPTOR_HPP
|
||||
|
||||
#include "descriptor_base.hpp"
|
||||
#include "description_factory.hpp"
|
||||
#include "../algorithms/object_encoder.hpp"
|
||||
#include "../algorithms/route_name_extraction.hpp"
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
#include "../data_structures/turn_instructions.hpp"
|
||||
#include "../util/bearing.hpp"
|
||||
#include "../util/cast.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/json_renderer.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
#include "../util/string_util.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
template <class DataFacadeT> class JSONDescriptor final : public BaseDescriptor<DataFacadeT>
|
||||
{
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
DescriptorConfig config;
|
||||
DescriptionFactory description_factory, alternate_description_factory;
|
||||
FixedPointCoordinate current;
|
||||
|
||||
public:
|
||||
struct Segment
|
||||
{
|
||||
Segment() : name_id(INVALID_NAMEID), length(-1), position(0) {}
|
||||
Segment(unsigned n, int l, unsigned p) : name_id(n), length(l), position(p) {}
|
||||
unsigned name_id;
|
||||
int length;
|
||||
unsigned position;
|
||||
};
|
||||
private:
|
||||
std::vector<Segment> shortest_path_segments, alternative_path_segments;
|
||||
ExtractRouteNames<DataFacadeT, Segment> GenerateRouteNames;
|
||||
|
||||
public:
|
||||
explicit JSONDescriptor(DataFacadeT *facade) : facade(facade)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void SetConfig(const DescriptorConfig &c) override final { config = c; }
|
||||
|
||||
unsigned DescribeLeg(const std::vector<PathData> &route_leg,
|
||||
const PhantomNodes &leg_phantoms,
|
||||
const bool target_traversed_in_reverse,
|
||||
const bool is_via_leg)
|
||||
{
|
||||
unsigned added_element_count = 0;
|
||||
// Get all the coordinates for the computed route
|
||||
FixedPointCoordinate current_coordinate;
|
||||
for (const PathData &path_data : route_leg)
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
description_factory.AppendSegment(current_coordinate, path_data);
|
||||
++added_element_count;
|
||||
}
|
||||
description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse,
|
||||
is_via_leg);
|
||||
++added_element_count;
|
||||
BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
|
||||
return added_element_count;
|
||||
}
|
||||
|
||||
virtual void Run(const InternalRouteResult &raw_route,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
|
||||
{
|
||||
// We do not need to do much, if there is no route ;-)
|
||||
return;
|
||||
}
|
||||
|
||||
// check if first segment is non-zero
|
||||
BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
|
||||
raw_route.segment_end_coordinates.size());
|
||||
|
||||
description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
|
||||
// for each unpacked segment add the leg to the description
|
||||
for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
const int added_segments =
|
||||
#endif
|
||||
DescribeLeg(raw_route.unpacked_path_segments[i],
|
||||
raw_route.segment_end_coordinates[i],
|
||||
raw_route.target_traversed_in_reverse[i], raw_route.is_via_leg(i));
|
||||
BOOST_ASSERT(0 < added_segments);
|
||||
}
|
||||
description_factory.Run(config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
osrm::json::Value route_geometry =
|
||||
description_factory.AppendGeometryString(config.encode_geometry);
|
||||
json_result.values["route_geometry"] = route_geometry;
|
||||
}
|
||||
if (config.instructions)
|
||||
{
|
||||
osrm::json::Array json_route_instructions = BuildTextualDescription(description_factory, shortest_path_segments);
|
||||
json_result.values["route_instructions"] = json_route_instructions;
|
||||
}
|
||||
description_factory.BuildRouteSummary(description_factory.get_entire_length(),
|
||||
raw_route.shortest_path_length);
|
||||
osrm::json::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = description_factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = description_factory.summary.duration;
|
||||
json_route_summary.values["start_point"] =
|
||||
facade->get_name_for_id(description_factory.summary.source_name_id);
|
||||
json_route_summary.values["end_point"] =
|
||||
facade->get_name_for_id(description_factory.summary.target_name_id);
|
||||
json_result.values["route_summary"] = json_route_summary;
|
||||
|
||||
BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());
|
||||
|
||||
osrm::json::Array json_via_points_array;
|
||||
osrm::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.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_first_coordinate);
|
||||
for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
|
||||
{
|
||||
std::string tmp;
|
||||
osrm::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.lon /
|
||||
COORDINATE_PRECISION);
|
||||
json_via_points_array.values.push_back(json_coordinate);
|
||||
}
|
||||
json_result.values["via_points"] = json_via_points_array;
|
||||
|
||||
osrm::json::Array json_via_indices_array;
|
||||
|
||||
std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
|
||||
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;
|
||||
|
||||
// only one alternative route is computed at this time, so this is hardcoded
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
json_result.values["found_alternative"] = osrm::json::True();
|
||||
BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
|
||||
alternate_description_factory.SetStartSegment(
|
||||
raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.front());
|
||||
// Get all the coordinates for the computed route
|
||||
for (const PathData &path_data : raw_route.unpacked_alternative)
|
||||
{
|
||||
current = facade->GetCoordinateOfNode(path_data.node);
|
||||
alternate_description_factory.AppendSegment(current, path_data);
|
||||
}
|
||||
alternate_description_factory.SetEndSegment(
|
||||
raw_route.segment_end_coordinates.back().target_phantom,
|
||||
raw_route.alt_source_traversed_in_reverse.back());
|
||||
alternate_description_factory.Run(config.zoom_level);
|
||||
|
||||
if (config.geometry)
|
||||
{
|
||||
osrm::json::Value alternate_geometry_string =
|
||||
alternate_description_factory.AppendGeometryString(config.encode_geometry);
|
||||
osrm::json::Array json_alternate_geometries_array;
|
||||
json_alternate_geometries_array.values.push_back(alternate_geometry_string);
|
||||
json_result.values["alternative_geometries"] = json_alternate_geometries_array;
|
||||
}
|
||||
// Generate instructions for each alternative (simulated here)
|
||||
osrm::json::Array json_alt_instructions;
|
||||
osrm::json::Array json_current_alt_instructions;
|
||||
if (config.instructions)
|
||||
{
|
||||
json_current_alt_instructions = BuildTextualDescription(alternate_description_factory, alternative_path_segments);
|
||||
json_alt_instructions.values.push_back(json_current_alt_instructions);
|
||||
json_result.values["alternative_instructions"] = json_alt_instructions;
|
||||
}
|
||||
alternate_description_factory.BuildRouteSummary(
|
||||
alternate_description_factory.get_entire_length(),
|
||||
raw_route.alternative_path_length);
|
||||
|
||||
osrm::json::Object json_alternate_route_summary;
|
||||
osrm::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_time"] =
|
||||
alternate_description_factory.summary.duration;
|
||||
json_alternate_route_summary.values["start_point"] =
|
||||
facade->get_name_for_id(alternate_description_factory.summary.source_name_id);
|
||||
json_alternate_route_summary.values["end_point"] =
|
||||
facade->get_name_for_id(alternate_description_factory.summary.target_name_id);
|
||||
json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
|
||||
json_result.values["alternative_summaries"] = json_alternate_route_summary_array;
|
||||
|
||||
std::vector<unsigned> const &alternate_leg_end_indices =
|
||||
alternate_description_factory.GetViaIndices();
|
||||
osrm::json::Array json_altenative_indices_array;
|
||||
json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
|
||||
alternate_leg_end_indices.begin(),
|
||||
alternate_leg_end_indices.end());
|
||||
json_result.values["alternative_indices"] = json_altenative_indices_array;
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["found_alternative"] = osrm::json::False();
|
||||
}
|
||||
|
||||
// Get Names for both routes
|
||||
RouteNames route_names =
|
||||
GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
|
||||
osrm::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_2);
|
||||
json_result.values["route_name"] = json_route_names;
|
||||
|
||||
if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
|
||||
{
|
||||
osrm::json::Array json_alternate_names_array;
|
||||
osrm::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_2);
|
||||
json_alternate_names_array.values.push_back(json_alternate_names);
|
||||
json_result.values["alternative_names"] = json_alternate_names_array;
|
||||
}
|
||||
|
||||
json_result.values["hint_data"] = BuildHintData(raw_route);
|
||||
}
|
||||
|
||||
inline osrm::json::Object BuildHintData(const InternalRouteResult& raw_route) const
|
||||
{
|
||||
osrm::json::Object json_hint_object;
|
||||
json_hint_object.values["checksum"] = facade->GetCheckSum();
|
||||
osrm::json::Array json_location_hint_array;
|
||||
std::string hint;
|
||||
for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
|
||||
{
|
||||
ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom,
|
||||
hint);
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
}
|
||||
ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom,
|
||||
hint);
|
||||
json_location_hint_array.values.push_back(hint);
|
||||
json_hint_object.values["locations"] = json_location_hint_array;
|
||||
|
||||
return json_hint_object;
|
||||
}
|
||||
|
||||
inline osrm::json::Array BuildTextualDescription(const DescriptionFactory &description_factory,
|
||||
std::vector<Segment> &route_segments_list) const
|
||||
{
|
||||
osrm::json::Array json_instruction_array;
|
||||
// Segment information has following format:
|
||||
//["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
unsigned necessary_segments_running_index = 0;
|
||||
|
||||
struct RoundAbout
|
||||
{
|
||||
RoundAbout() : start_index(std::numeric_limits<int>::max()), name_id(INVALID_NAMEID), leave_at_exit(std::numeric_limits<int>::max()) {}
|
||||
int start_index;
|
||||
unsigned name_id;
|
||||
int leave_at_exit;
|
||||
} round_about;
|
||||
|
||||
round_about.leave_at_exit = 0;
|
||||
round_about.name_id = 0;
|
||||
std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
|
||||
|
||||
// Fetch data from Factory and generate a string from it.
|
||||
for (const SegmentInformation &segment : description_factory.path_description)
|
||||
{
|
||||
osrm::json::Array json_instruction_row;
|
||||
TurnInstruction current_instruction = segment.turn_instruction;
|
||||
if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
|
||||
{
|
||||
if (TurnInstruction::EnterRoundAbout == current_instruction)
|
||||
{
|
||||
round_about.name_id = segment.name_id;
|
||||
round_about.start_index = necessary_segments_running_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string current_turn_instruction;
|
||||
if (TurnInstruction::LeaveRoundAbout == current_instruction)
|
||||
{
|
||||
temp_instruction = std::to_string(
|
||||
cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
|
||||
current_turn_instruction += temp_instruction;
|
||||
current_turn_instruction += "-";
|
||||
temp_instruction = std::to_string(round_about.leave_at_exit + 1);
|
||||
current_turn_instruction += temp_instruction;
|
||||
round_about.leave_at_exit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(current_instruction));
|
||||
current_turn_instruction += temp_instruction;
|
||||
}
|
||||
json_instruction_row.values.push_back(current_turn_instruction);
|
||||
|
||||
json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id));
|
||||
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(std::round(segment.duration / 10.));
|
||||
json_instruction_row.values.push_back(
|
||||
std::to_string(static_cast<unsigned>(segment.length)) + "m");
|
||||
|
||||
// post turn bearing
|
||||
const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
|
||||
json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<unsigned>(round(post_turn_bearing_value)));
|
||||
|
||||
json_instruction_row.values.push_back(segment.travel_mode);
|
||||
|
||||
// pre turn bearing
|
||||
const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
|
||||
json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value));
|
||||
json_instruction_row.values.push_back(
|
||||
static_cast<unsigned>(round(pre_turn_bearing_value)));
|
||||
|
||||
json_instruction_array.values.push_back(json_instruction_row);
|
||||
|
||||
route_segments_list.emplace_back(
|
||||
segment.name_id, static_cast<int>(segment.length),
|
||||
static_cast<unsigned>(route_segments_list.size()));
|
||||
}
|
||||
}
|
||||
else if (TurnInstruction::StayOnRoundAbout == current_instruction)
|
||||
{
|
||||
++round_about.leave_at_exit;
|
||||
}
|
||||
if (segment.necessary)
|
||||
{
|
||||
++necessary_segments_running_index;
|
||||
}
|
||||
}
|
||||
|
||||
osrm::json::Array json_last_instruction_row;
|
||||
temp_instruction =
|
||||
std::to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
|
||||
json_last_instruction_row.values.push_back(temp_instruction);
|
||||
json_last_instruction_row.values.push_back("");
|
||||
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(0);
|
||||
json_last_instruction_row.values.push_back("0m");
|
||||
json_last_instruction_row.values.push_back(bearing::get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_last_instruction_row.values.push_back(bearing::get(0.0));
|
||||
json_last_instruction_row.values.push_back(0.);
|
||||
json_instruction_array.values.push_back(json_last_instruction_row);
|
||||
|
||||
return json_instruction_array;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DOUGLAS_PEUCKER_HPP_
|
||||
#define DOUGLAS_PEUCKER_HPP_
|
||||
|
||||
#include "../data_structures/segment_information.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/* This class object computes the bitvector of indicating generalized input
|
||||
* points according to the (Ramer-)Douglas-Peucker algorithm.
|
||||
*
|
||||
* Input is vector of pairs. Each pair consists of the point information and a
|
||||
* bit indicating if the points is present in the generalization.
|
||||
* Note: points may also be pre-selected*/
|
||||
|
||||
static const std::array<int, 19> DOUGLAS_PEUCKER_THRESHOLDS{{
|
||||
512440, // z0
|
||||
256720, // z1
|
||||
122560, // z2
|
||||
56780, // z3
|
||||
28800, // z4
|
||||
14400, // z5
|
||||
7200, // z6
|
||||
3200, // z7
|
||||
2400, // z8
|
||||
1000, // z9
|
||||
600, // z10
|
||||
120, // z11
|
||||
60, // z12
|
||||
45, // z13
|
||||
36, // z14
|
||||
20, // z15
|
||||
8, // z16
|
||||
6, // z17
|
||||
4 // z18
|
||||
}};
|
||||
|
||||
class DouglasPeucker
|
||||
{
|
||||
public:
|
||||
using RandomAccessIt = std::vector<SegmentInformation>::iterator;
|
||||
|
||||
using GeometryRange = std::pair<RandomAccessIt, RandomAccessIt>;
|
||||
// Stack to simulate the recursion
|
||||
std::stack<GeometryRange> recursion_stack;
|
||||
|
||||
public:
|
||||
void Run(RandomAccessIt begin, RandomAccessIt end, const unsigned zoom_level);
|
||||
void Run(std::vector<SegmentInformation> &input_geometry, const unsigned zoom_level);
|
||||
};
|
||||
|
||||
#endif /* DOUGLAS_PEUCKER_HPP_ */
|
||||
@@ -0,0 +1,180 @@
|
||||
#ifndef GEOSPATIAL_QUERY_HPP
|
||||
#define GEOSPATIAL_QUERY_HPP
|
||||
|
||||
#include "coordinate_calculation.hpp"
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
#include "../util/bearing.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
// Implements complex queries on top of an RTree and builds PhantomNodes from it.
|
||||
//
|
||||
// Only holds a weak reference on the RTree!
|
||||
template <typename RTreeT> class GeospatialQuery
|
||||
{
|
||||
using EdgeData = typename RTreeT::EdgeData;
|
||||
using CoordinateList = typename RTreeT::CoordinateList;
|
||||
|
||||
public:
|
||||
GeospatialQuery(RTreeT &rtree_, std::shared_ptr<CoordinateList> coordinates_)
|
||||
: rtree(rtree_), coordinates(coordinates_)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns nearest PhantomNodes in the given bearing range within max_distance.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodesInRange(const FixedPointCoordinate &input_coordinate,
|
||||
const float max_distance,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180)
|
||||
{
|
||||
auto results =
|
||||
rtree.Nearest(input_coordinate,
|
||||
[this, bearing, bearing_range, max_distance](const EdgeData &data)
|
||||
{
|
||||
return checkSegmentBearing(data, bearing, bearing_range);
|
||||
},
|
||||
[max_distance](const std::size_t, const float min_dist)
|
||||
{
|
||||
return min_dist > max_distance;
|
||||
});
|
||||
|
||||
return MakePhantomNodes(input_coordinate, results);
|
||||
}
|
||||
|
||||
// Returns max_results nearest PhantomNodes in the given bearing range.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const unsigned max_results,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180)
|
||||
{
|
||||
auto results = rtree.Nearest(input_coordinate,
|
||||
[this, bearing, bearing_range](const EdgeData &data)
|
||||
{
|
||||
return checkSegmentBearing(data, bearing, bearing_range);
|
||||
},
|
||||
[max_results](const std::size_t num_results, const float)
|
||||
{
|
||||
return num_results >= max_results;
|
||||
});
|
||||
|
||||
return MakePhantomNodes(input_coordinate, results);
|
||||
}
|
||||
|
||||
// Returns the nearest phantom node. If this phantom node is not from a big component
|
||||
// a second phantom node is return that is the nearest coordinate in a big component.
|
||||
std::pair<PhantomNode, PhantomNode>
|
||||
NearestPhantomNodeWithAlternativeFromBigComponent(const FixedPointCoordinate &input_coordinate,
|
||||
const int bearing = 0,
|
||||
const int bearing_range = 180)
|
||||
{
|
||||
bool has_small_component = false;
|
||||
bool has_big_component = false;
|
||||
auto results = rtree.Nearest(
|
||||
input_coordinate,
|
||||
[this, bearing, bearing_range, &has_big_component,
|
||||
&has_small_component](const EdgeData &data)
|
||||
{
|
||||
auto use_segment =
|
||||
(!has_small_component || (!has_big_component && !data.component.is_tiny));
|
||||
auto use_directions = std::make_pair(use_segment, use_segment);
|
||||
|
||||
if (use_segment)
|
||||
{
|
||||
use_directions = checkSegmentBearing(data, bearing, bearing_range);
|
||||
if (use_directions.first || use_directions.second)
|
||||
{
|
||||
has_big_component = has_big_component || !data.component.is_tiny;
|
||||
has_small_component = has_small_component || data.component.is_tiny;
|
||||
}
|
||||
}
|
||||
|
||||
return use_directions;
|
||||
},
|
||||
[&has_big_component](const std::size_t num_results, const float)
|
||||
{
|
||||
return num_results > 0 && has_big_component;
|
||||
});
|
||||
|
||||
if (results.size() == 0)
|
||||
{
|
||||
return std::make_pair(PhantomNode{}, PhantomNode{});
|
||||
}
|
||||
|
||||
BOOST_ASSERT(results.size() > 0);
|
||||
return std::make_pair(MakePhantomNode(input_coordinate, results.front()).phantom_node,
|
||||
MakePhantomNode(input_coordinate, results.back()).phantom_node);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
MakePhantomNodes(const FixedPointCoordinate &input_coordinate,
|
||||
const std::vector<EdgeData> &results) const
|
||||
{
|
||||
std::vector<PhantomNodeWithDistance> distance_and_phantoms(results.size());
|
||||
std::transform(results.begin(), results.end(), distance_and_phantoms.begin(),
|
||||
[this, &input_coordinate](const EdgeData &data)
|
||||
{
|
||||
return MakePhantomNode(input_coordinate, data);
|
||||
});
|
||||
return distance_and_phantoms;
|
||||
}
|
||||
|
||||
PhantomNodeWithDistance MakePhantomNode(const FixedPointCoordinate &input_coordinate,
|
||||
const EdgeData &data) const
|
||||
{
|
||||
FixedPointCoordinate point_on_segment;
|
||||
float ratio;
|
||||
const auto current_perpendicular_distance = coordinate_calculation::perpendicular_distance(
|
||||
coordinates->at(data.u), coordinates->at(data.v), input_coordinate, point_on_segment,
|
||||
ratio);
|
||||
|
||||
auto transformed =
|
||||
PhantomNodeWithDistance { PhantomNode{data, point_on_segment}, current_perpendicular_distance };
|
||||
|
||||
ratio = std::min(1.f, std::max(0.f, ratio));
|
||||
|
||||
if (SPECIAL_NODEID != transformed.phantom_node.forward_node_id)
|
||||
{
|
||||
transformed.phantom_node.forward_weight *= ratio;
|
||||
}
|
||||
if (SPECIAL_NODEID != transformed.phantom_node.reverse_node_id)
|
||||
{
|
||||
transformed.phantom_node.reverse_weight *= 1.f - ratio;
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> checkSegmentBearing(const EdgeData &segment,
|
||||
const float filter_bearing,
|
||||
const float filter_bearing_range)
|
||||
{
|
||||
const float forward_edge_bearing =
|
||||
coordinate_calculation::bearing(coordinates->at(segment.u), coordinates->at(segment.v));
|
||||
|
||||
const float backward_edge_bearing = (forward_edge_bearing + 180) > 360
|
||||
? (forward_edge_bearing - 180)
|
||||
: (forward_edge_bearing + 180);
|
||||
|
||||
const bool forward_bearing_valid =
|
||||
bearing::CheckInBounds(forward_edge_bearing, filter_bearing, filter_bearing_range) &&
|
||||
segment.forward_edge_based_node_id != SPECIAL_NODEID;
|
||||
const bool backward_bearing_valid =
|
||||
bearing::CheckInBounds(backward_edge_bearing, filter_bearing, filter_bearing_range) &&
|
||||
segment.reverse_edge_based_node_id != SPECIAL_NODEID;
|
||||
return std::make_pair(forward_bearing_valid, backward_bearing_valid);
|
||||
}
|
||||
|
||||
RTreeT &rtree;
|
||||
const std::shared_ptr<CoordinateList> coordinates;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RAW_ROUTE_DATA_H
|
||||
#define RAW_ROUTE_DATA_H
|
||||
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
#include "../data_structures/travel_mode.hpp"
|
||||
#include "../data_structures/turn_instructions.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct PathData
|
||||
{
|
||||
PathData()
|
||||
: node(SPECIAL_NODEID), name_id(INVALID_EDGE_WEIGHT), segment_duration(INVALID_EDGE_WEIGHT),
|
||||
turn_instruction(TurnInstruction::NoTurn), travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
}
|
||||
|
||||
PathData(NodeID node,
|
||||
unsigned name_id,
|
||||
TurnInstruction turn_instruction,
|
||||
EdgeWeight segment_duration,
|
||||
TravelMode travel_mode)
|
||||
: node(node), name_id(name_id), segment_duration(segment_duration),
|
||||
turn_instruction(turn_instruction), travel_mode(travel_mode)
|
||||
{
|
||||
}
|
||||
NodeID node;
|
||||
unsigned name_id;
|
||||
EdgeWeight segment_duration;
|
||||
TurnInstruction turn_instruction;
|
||||
TravelMode travel_mode : 4;
|
||||
};
|
||||
|
||||
struct InternalRouteResult
|
||||
{
|
||||
std::vector<std::vector<PathData>> unpacked_path_segments;
|
||||
std::vector<PathData> unpacked_alternative;
|
||||
std::vector<PhantomNodes> segment_end_coordinates;
|
||||
std::vector<bool> source_traversed_in_reverse;
|
||||
std::vector<bool> target_traversed_in_reverse;
|
||||
std::vector<bool> alt_source_traversed_in_reverse;
|
||||
std::vector<bool> alt_target_traversed_in_reverse;
|
||||
int shortest_path_length;
|
||||
int alternative_path_length;
|
||||
|
||||
bool is_via_leg(const std::size_t leg) const
|
||||
{
|
||||
return (leg != unpacked_path_segments.size() - 1);
|
||||
}
|
||||
|
||||
InternalRouteResult()
|
||||
: shortest_path_length(INVALID_EDGE_WEIGHT), alternative_path_length(INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RAW_ROUTE_DATA_H
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BAYES_CLASSIFIER_HPP
|
||||
#define BAYES_CLASSIFIER_HPP
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
struct NormalDistribution
|
||||
{
|
||||
NormalDistribution(const double mean, const double standard_deviation)
|
||||
: mean(mean), standard_deviation(standard_deviation)
|
||||
{
|
||||
}
|
||||
|
||||
// FIXME implement log-probability version since its faster
|
||||
double density_function(const double val) const
|
||||
{
|
||||
const double x = val - mean;
|
||||
return 1.0 / (std::sqrt(2. * M_PI) * standard_deviation) *
|
||||
std::exp(-x * x / (standard_deviation * standard_deviation));
|
||||
}
|
||||
|
||||
double mean;
|
||||
double standard_deviation;
|
||||
};
|
||||
|
||||
struct LaplaceDistribution
|
||||
{
|
||||
LaplaceDistribution(const double location, const double scale)
|
||||
: location(location), scale(scale)
|
||||
{
|
||||
}
|
||||
|
||||
// FIXME implement log-probability version since its faster
|
||||
double density_function(const double val) const
|
||||
{
|
||||
const double x = std::abs(val - location);
|
||||
return 1.0 / (2. * scale) * std::exp(-x / scale);
|
||||
}
|
||||
|
||||
double location;
|
||||
double scale;
|
||||
};
|
||||
|
||||
template <typename PositiveDistributionT, typename NegativeDistributionT, typename ValueT>
|
||||
class BayesClassifier
|
||||
{
|
||||
public:
|
||||
enum class ClassLabel : unsigned
|
||||
{
|
||||
NEGATIVE,
|
||||
POSITIVE
|
||||
};
|
||||
using ClassificationT = std::pair<ClassLabel, double>;
|
||||
|
||||
BayesClassifier(PositiveDistributionT positive_distribution,
|
||||
NegativeDistributionT negative_distribution,
|
||||
const double positive_apriori_probability)
|
||||
: positive_distribution(std::move(positive_distribution)),
|
||||
negative_distribution(std::move(negative_distribution)),
|
||||
positive_apriori_probability(positive_apriori_probability),
|
||||
negative_apriori_probability(1. - positive_apriori_probability)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns label and the probability of the label.
|
||||
ClassificationT classify(const ValueT &v) const
|
||||
{
|
||||
const double positive_postpriori =
|
||||
positive_apriori_probability * positive_distribution.density_function(v);
|
||||
const double negative_postpriori =
|
||||
negative_apriori_probability * negative_distribution.density_function(v);
|
||||
const double norm = positive_postpriori + negative_postpriori;
|
||||
|
||||
if (positive_postpriori > negative_postpriori)
|
||||
{
|
||||
return std::make_pair(ClassLabel::POSITIVE, positive_postpriori / norm);
|
||||
}
|
||||
|
||||
return std::make_pair(ClassLabel::NEGATIVE, negative_postpriori / norm);
|
||||
}
|
||||
|
||||
private:
|
||||
PositiveDistributionT positive_distribution;
|
||||
NegativeDistributionT negative_distribution;
|
||||
double positive_apriori_probability;
|
||||
double negative_apriori_probability;
|
||||
};
|
||||
|
||||
#endif // BAYES_CLASSIFIER_HPP
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HIDDEN_MARKOV_MODEL
|
||||
#define HIDDEN_MARKOV_MODEL
|
||||
|
||||
#include "../util/integer_range.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace matching
|
||||
{
|
||||
static const double log_2_pi = std::log(2. * M_PI);
|
||||
static const double IMPOSSIBLE_LOG_PROB = -std::numeric_limits<double>::infinity();
|
||||
static const double MINIMAL_LOG_PROB = std::numeric_limits<double>::lowest();
|
||||
static const std::size_t INVALID_STATE = std::numeric_limits<std::size_t>::max();
|
||||
} // namespace matching
|
||||
} // namespace osrm
|
||||
|
||||
// closures to precompute log -> only simple floating point operations
|
||||
struct EmissionLogProbability
|
||||
{
|
||||
double sigma_z;
|
||||
double log_sigma_z;
|
||||
|
||||
EmissionLogProbability(const double sigma_z) : sigma_z(sigma_z), log_sigma_z(std::log(sigma_z))
|
||||
{
|
||||
}
|
||||
|
||||
double operator()(const double distance) const
|
||||
{
|
||||
return -0.5 * (osrm::matching::log_2_pi + (distance / sigma_z) * (distance / sigma_z)) -
|
||||
log_sigma_z;
|
||||
}
|
||||
};
|
||||
|
||||
struct TransitionLogProbability
|
||||
{
|
||||
double beta;
|
||||
double log_beta;
|
||||
TransitionLogProbability(const double beta) : beta(beta), log_beta(std::log(beta)) {}
|
||||
|
||||
double operator()(const double d_t) const { return -log_beta - d_t / beta; }
|
||||
};
|
||||
|
||||
template <class CandidateLists> struct HiddenMarkovModel
|
||||
{
|
||||
std::vector<std::vector<double>> viterbi;
|
||||
std::vector<std::vector<std::pair<unsigned, unsigned>>> parents;
|
||||
std::vector<std::vector<float>> path_lengths;
|
||||
std::vector<std::vector<bool>> pruned;
|
||||
std::vector<std::vector<bool>> suspicious;
|
||||
std::vector<bool> breakage;
|
||||
|
||||
const CandidateLists &candidates_list;
|
||||
const EmissionLogProbability &emission_log_probability;
|
||||
|
||||
HiddenMarkovModel(const CandidateLists &candidates_list,
|
||||
const EmissionLogProbability &emission_log_probability)
|
||||
: breakage(candidates_list.size()), candidates_list(candidates_list),
|
||||
emission_log_probability(emission_log_probability)
|
||||
{
|
||||
viterbi.resize(candidates_list.size());
|
||||
parents.resize(candidates_list.size());
|
||||
path_lengths.resize(candidates_list.size());
|
||||
suspicious.resize(candidates_list.size());
|
||||
pruned.resize(candidates_list.size());
|
||||
breakage.resize(candidates_list.size());
|
||||
for (const auto i : osrm::irange<std::size_t>(0u, candidates_list.size()))
|
||||
{
|
||||
const auto& num_candidates = candidates_list[i].size();
|
||||
// add empty vectors
|
||||
if (num_candidates > 0)
|
||||
{
|
||||
viterbi[i].resize(num_candidates);
|
||||
parents[i].resize(num_candidates);
|
||||
path_lengths[i].resize(num_candidates);
|
||||
suspicious[i].resize(num_candidates);
|
||||
pruned[i].resize(num_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
clear(0);
|
||||
}
|
||||
|
||||
void clear(std::size_t initial_timestamp)
|
||||
{
|
||||
BOOST_ASSERT(viterbi.size() == parents.size() && parents.size() == path_lengths.size() &&
|
||||
path_lengths.size() == pruned.size() && pruned.size() == breakage.size());
|
||||
|
||||
for (const auto t : osrm::irange(initial_timestamp, viterbi.size()))
|
||||
{
|
||||
std::fill(viterbi[t].begin(), viterbi[t].end(), osrm::matching::IMPOSSIBLE_LOG_PROB);
|
||||
std::fill(parents[t].begin(), parents[t].end(), std::make_pair(0u, 0u));
|
||||
std::fill(path_lengths[t].begin(), path_lengths[t].end(), 0);
|
||||
std::fill(suspicious[t].begin(), suspicious[t].end(), true);
|
||||
std::fill(pruned[t].begin(), pruned[t].end(), true);
|
||||
}
|
||||
std::fill(breakage.begin() + initial_timestamp, breakage.end(), true);
|
||||
}
|
||||
|
||||
std::size_t initialize(std::size_t initial_timestamp)
|
||||
{
|
||||
auto num_points = candidates_list.size();
|
||||
do
|
||||
{
|
||||
BOOST_ASSERT(initial_timestamp < num_points);
|
||||
|
||||
for (const auto s : osrm::irange<std::size_t>(0u, viterbi[initial_timestamp].size()))
|
||||
{
|
||||
viterbi[initial_timestamp][s] =
|
||||
emission_log_probability(candidates_list[initial_timestamp][s].distance);
|
||||
parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
|
||||
pruned[initial_timestamp][s] =
|
||||
viterbi[initial_timestamp][s] < osrm::matching::MINIMAL_LOG_PROB;
|
||||
suspicious[initial_timestamp][s] = false;
|
||||
|
||||
breakage[initial_timestamp] =
|
||||
breakage[initial_timestamp] && pruned[initial_timestamp][s];
|
||||
}
|
||||
|
||||
++initial_timestamp;
|
||||
} while (initial_timestamp < num_points && breakage[initial_timestamp - 1]);
|
||||
|
||||
if (initial_timestamp >= num_points)
|
||||
{
|
||||
return osrm::matching::INVALID_STATE;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(initial_timestamp > 0);
|
||||
--initial_timestamp;
|
||||
|
||||
BOOST_ASSERT(breakage[initial_timestamp] == false);
|
||||
|
||||
return initial_timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // HIDDEN_MARKOV_MODEL
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OBJECT_ENCODER_HPP
|
||||
#define OBJECT_ENCODER_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/archive/iterators/base64_from_binary.hpp>
|
||||
#include <boost/archive/iterators/binary_from_base64.hpp>
|
||||
#include <boost/archive/iterators/transform_width.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ObjectEncoder
|
||||
{
|
||||
using base64_t = boost::archive::iterators::base64_from_binary<
|
||||
boost::archive::iterators::transform_width<const char *, 6, 8>>;
|
||||
|
||||
using binary_t = boost::archive::iterators::transform_width<
|
||||
boost::archive::iterators::binary_from_base64<std::string::const_iterator>,
|
||||
8,
|
||||
6>;
|
||||
|
||||
template <class ObjectT> static void EncodeToBase64(const ObjectT &object, std::string &encoded)
|
||||
{
|
||||
const char *char_ptr_to_object = reinterpret_cast<const char *>(&object);
|
||||
std::vector<unsigned char> data(sizeof(object));
|
||||
std::copy(char_ptr_to_object, char_ptr_to_object + sizeof(ObjectT), data.begin());
|
||||
|
||||
unsigned char number_of_padded_chars = 0; // is in {0,1,2};
|
||||
while (data.size() % 3 != 0)
|
||||
{
|
||||
++number_of_padded_chars;
|
||||
data.push_back(0x00);
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(0 == data.size() % 3, "base64 input data size is not a multiple of 3!");
|
||||
encoded.resize(sizeof(ObjectT));
|
||||
encoded.assign(base64_t(&data[0]),
|
||||
base64_t(&data[0] + (data.size() - number_of_padded_chars)));
|
||||
std::replace(begin(encoded), end(encoded), '+', '-');
|
||||
std::replace(begin(encoded), end(encoded), '/', '_');
|
||||
}
|
||||
|
||||
template <class ObjectT> static void DecodeFromBase64(const std::string &input, ObjectT &object)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string encoded(input);
|
||||
std::replace(begin(encoded), end(encoded), '-', '+');
|
||||
std::replace(begin(encoded), end(encoded), '_', '/');
|
||||
|
||||
std::copy(binary_t(encoded.begin()), binary_t(encoded.begin() + encoded.length()),
|
||||
reinterpret_cast<char *>(&object));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* OBJECT_ENCODER_HPP */
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OSRM_IMPL_HPP
|
||||
#define OSRM_IMPL_HPP
|
||||
|
||||
class BasePlugin;
|
||||
struct RouteParameters;
|
||||
|
||||
#include "../data_structures/query_edge.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
#include <osrm/libosrm_config.hpp>
|
||||
#include <osrm/osrm.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
struct SharedBarriers;
|
||||
template <class EdgeDataT> class BaseDataFacade;
|
||||
|
||||
class OSRM::OSRM_impl final
|
||||
{
|
||||
private:
|
||||
using PluginMap = std::unordered_map<std::string, std::unique_ptr<BasePlugin>>;
|
||||
|
||||
public:
|
||||
OSRM_impl(LibOSRMConfig &lib_config);
|
||||
OSRM_impl(const OSRM_impl &) = delete;
|
||||
int RunQuery(const RouteParameters &route_parameters, osrm::json::Object &json_result);
|
||||
|
||||
private:
|
||||
void RegisterPlugin(BasePlugin *plugin);
|
||||
PluginMap plugin_map;
|
||||
// will only be initialized if shared memory is used
|
||||
std::unique_ptr<SharedBarriers> barrier;
|
||||
// base class pointer to the objects
|
||||
BaseDataFacade<QueryEdge::EdgeData> *query_data_facade;
|
||||
|
||||
// decrease number of concurrent queries
|
||||
void decrease_concurrent_query_count();
|
||||
// increase number of concurrent queries
|
||||
void increase_concurrent_query_count();
|
||||
};
|
||||
|
||||
#endif // OSRM_IMPL_HPP
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef PHANTOM_NODES_H
|
||||
#define PHANTOM_NODES_H
|
||||
|
||||
#include "travel_mode.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
struct PhantomNode
|
||||
{
|
||||
PhantomNode(NodeID forward_node_id,
|
||||
NodeID reverse_node_id,
|
||||
unsigned name_id,
|
||||
int forward_weight,
|
||||
int reverse_weight,
|
||||
int forward_offset,
|
||||
int reverse_offset,
|
||||
unsigned packed_geometry_id,
|
||||
bool is_tiny_component,
|
||||
unsigned component_id,
|
||||
FixedPointCoordinate &location,
|
||||
unsigned short fwd_segment_position,
|
||||
TravelMode forward_travel_mode,
|
||||
TravelMode backward_travel_mode);
|
||||
|
||||
PhantomNode();
|
||||
|
||||
template <class OtherT> PhantomNode(const OtherT &other, const FixedPointCoordinate &foot_point)
|
||||
{
|
||||
forward_node_id = other.forward_edge_based_node_id;
|
||||
reverse_node_id = other.reverse_edge_based_node_id;
|
||||
name_id = other.name_id;
|
||||
|
||||
forward_weight = other.forward_weight;
|
||||
reverse_weight = other.reverse_weight;
|
||||
|
||||
forward_offset = other.forward_offset;
|
||||
reverse_offset = other.reverse_offset;
|
||||
|
||||
packed_geometry_id = other.packed_geometry_id;
|
||||
|
||||
component.id = other.component.id;
|
||||
component.is_tiny = other.component.is_tiny;
|
||||
|
||||
location = foot_point;
|
||||
fwd_segment_position = other.fwd_segment_position;
|
||||
|
||||
forward_travel_mode = other.forward_travel_mode;
|
||||
backward_travel_mode = other.backward_travel_mode;
|
||||
}
|
||||
|
||||
NodeID forward_node_id;
|
||||
NodeID reverse_node_id;
|
||||
unsigned name_id;
|
||||
int forward_weight;
|
||||
int reverse_weight;
|
||||
int forward_offset;
|
||||
int reverse_offset;
|
||||
unsigned packed_geometry_id;
|
||||
struct ComponentType {
|
||||
uint32_t id : 31;
|
||||
bool is_tiny : 1;
|
||||
} component;
|
||||
// bit-fields are broken on Windows
|
||||
#ifndef _MSC_VER
|
||||
static_assert(sizeof(ComponentType) == 4, "ComponentType needs to 4 bytes big");
|
||||
#endif
|
||||
FixedPointCoordinate location;
|
||||
unsigned short fwd_segment_position;
|
||||
// note 4 bits would suffice for each,
|
||||
// but the saved byte would be padding anyway
|
||||
TravelMode forward_travel_mode;
|
||||
TravelMode backward_travel_mode;
|
||||
|
||||
int GetForwardWeightPlusOffset() const;
|
||||
|
||||
int GetReverseWeightPlusOffset() const;
|
||||
|
||||
bool is_bidirected() const;
|
||||
|
||||
bool is_compressed() const;
|
||||
|
||||
bool is_valid(const unsigned numberOfNodes) const;
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
bool operator==(const PhantomNode &other) const;
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
static_assert(sizeof(PhantomNode) == 48, "PhantomNode has more padding then expected");
|
||||
#endif
|
||||
|
||||
using PhantomNodePair = std::pair<PhantomNode, PhantomNode>;
|
||||
|
||||
struct PhantomNodeWithDistance
|
||||
{
|
||||
PhantomNode phantom_node;
|
||||
double distance;
|
||||
};
|
||||
|
||||
struct PhantomNodes
|
||||
{
|
||||
PhantomNode source_phantom;
|
||||
PhantomNode target_phantom;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, const PhantomNodes &pn)
|
||||
{
|
||||
out << "source_coord: " << pn.source_phantom.location << "\n";
|
||||
out << "target_coord: " << pn.target_phantom.location << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, const PhantomNode &pn)
|
||||
{
|
||||
out << "node1: " << pn.forward_node_id << ", "
|
||||
<< "node2: " << pn.reverse_node_id << ", "
|
||||
<< "name: " << pn.name_id << ", "
|
||||
<< "fwd-w: " << pn.forward_weight << ", "
|
||||
<< "rev-w: " << pn.reverse_weight << ", "
|
||||
<< "fwd-o: " << pn.forward_offset << ", "
|
||||
<< "rev-o: " << pn.reverse_offset << ", "
|
||||
<< "geom: " << pn.packed_geometry_id << ", "
|
||||
<< "comp: " << pn.component.is_tiny << " / " << pn.component.id << ", "
|
||||
<< "pos: " << pn.fwd_segment_position << ", "
|
||||
<< "loc: " << pn.location;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif // PHANTOM_NODES_H
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DISTANCE_TABLE_HPP
|
||||
#define DISTANCE_TABLE_HPP
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../algorithms/object_encoder.hpp"
|
||||
#include "../data_structures/query_edge.hpp"
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../descriptors/descriptor_base.hpp"
|
||||
#include "../util/json_renderer.hpp"
|
||||
#include "../util/make_unique.hpp"
|
||||
#include "../util/string_util.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
int max_locations_distance_table;
|
||||
|
||||
public:
|
||||
explicit DistanceTablePlugin(DataFacadeT *facade, const int max_locations_distance_table)
|
||||
: max_locations_distance_table(max_locations_distance_table), descriptor_string("table"),
|
||||
facade(facade)
|
||||
{
|
||||
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
|
||||
}
|
||||
|
||||
virtual ~DistanceTablePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
|
||||
Status HandleRequest(const RouteParameters &route_parameters,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
if (!check_all_coordinates(route_parameters.coordinates))
|
||||
{
|
||||
json_result.values["status_message"] = "Coordinates are invalid";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_bearings.size() > 0 &&
|
||||
route_parameters.coordinates.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of bearings does not match number of coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
auto number_of_sources =
|
||||
std::count_if(route_parameters.is_source.begin(), route_parameters.is_source.end(),
|
||||
[](const bool is_source)
|
||||
{
|
||||
return is_source;
|
||||
});
|
||||
auto number_of_destination =
|
||||
std::count_if(route_parameters.is_destination.begin(),
|
||||
route_parameters.is_destination.end(), [](const bool is_destination)
|
||||
{
|
||||
return is_destination;
|
||||
});
|
||||
|
||||
if (max_locations_distance_table > 0 &&
|
||||
(number_of_sources * number_of_destination >
|
||||
max_locations_distance_table * max_locations_distance_table))
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of entries " + std::to_string(number_of_sources * number_of_destination) +
|
||||
" is higher than current maximum (" +
|
||||
std::to_string(max_locations_distance_table * max_locations_distance_table) + ")";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
|
||||
|
||||
std::vector<PhantomNodePair> phantom_node_source_vector(number_of_sources);
|
||||
std::vector<PhantomNodePair> phantom_node_target_vector(number_of_destination);
|
||||
auto phantom_node_source_out_iter = phantom_node_source_vector.begin();
|
||||
auto phantom_node_target_out_iter = phantom_node_target_vector.begin();
|
||||
for (const auto i : osrm::irange<std::size_t>(0u, route_parameters.coordinates.size()))
|
||||
{
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
PhantomNode current_phantom_node;
|
||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
|
||||
if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
if (route_parameters.is_source[i])
|
||||
{
|
||||
*phantom_node_source_out_iter =
|
||||
std::make_pair(current_phantom_node, current_phantom_node);
|
||||
if (route_parameters.is_destination[i])
|
||||
{
|
||||
*phantom_node_target_out_iter = *phantom_node_source_out_iter;
|
||||
phantom_node_target_out_iter++;
|
||||
}
|
||||
phantom_node_source_out_iter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(route_parameters.is_destination[i] &&
|
||||
!route_parameters.is_source[i]);
|
||||
*phantom_node_target_out_iter =
|
||||
std::make_pair(current_phantom_node, current_phantom_node);
|
||||
phantom_node_target_out_iter++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
|
||||
const int range = input_bearings.size() > 0
|
||||
? (input_bearings[i].second ? *input_bearings[i].second : 10)
|
||||
: 180;
|
||||
if (route_parameters.is_source[i])
|
||||
{
|
||||
*phantom_node_source_out_iter =
|
||||
facade->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
route_parameters.coordinates[i], bearing, range);
|
||||
// we didn't found a fitting node, return error
|
||||
if (!phantom_node_source_out_iter->first.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
|
||||
return Status::NoSegment;
|
||||
}
|
||||
|
||||
if (route_parameters.is_destination[i])
|
||||
{
|
||||
*phantom_node_target_out_iter = *phantom_node_source_out_iter;
|
||||
phantom_node_target_out_iter++;
|
||||
}
|
||||
phantom_node_source_out_iter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]);
|
||||
|
||||
*phantom_node_target_out_iter =
|
||||
facade->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
route_parameters.coordinates[i], bearing, range);
|
||||
// we didn't found a fitting node, return error
|
||||
if (!phantom_node_target_out_iter->first.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
|
||||
return Status::NoSegment;
|
||||
}
|
||||
phantom_node_target_out_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) ==
|
||||
number_of_sources);
|
||||
BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) ==
|
||||
number_of_destination);
|
||||
|
||||
// FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after
|
||||
// this
|
||||
auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector);
|
||||
auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector);
|
||||
|
||||
auto result_table =
|
||||
search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms);
|
||||
|
||||
if (!result_table)
|
||||
{
|
||||
json_result.values["status_message"] = "No distance table found";
|
||||
return Status::EmptyResult;
|
||||
}
|
||||
|
||||
osrm::json::Array matrix_json_array;
|
||||
for (const auto row : osrm::irange<std::size_t>(0, number_of_sources))
|
||||
{
|
||||
osrm::json::Array json_row;
|
||||
auto row_begin_iterator = result_table->begin() + (row * number_of_destination);
|
||||
auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_destination);
|
||||
json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
|
||||
matrix_json_array.values.push_back(json_row);
|
||||
}
|
||||
json_result.values["distance_table"] = matrix_json_array;
|
||||
|
||||
osrm::json::Array target_coord_json_array;
|
||||
for (const auto &phantom : snapped_target_phantoms)
|
||||
{
|
||||
osrm::json::Array json_coord;
|
||||
json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
|
||||
target_coord_json_array.values.push_back(json_coord);
|
||||
}
|
||||
json_result.values["destination_coordinates"] = target_coord_json_array;
|
||||
osrm::json::Array source_coord_json_array;
|
||||
for (const auto &phantom : snapped_source_phantoms)
|
||||
{
|
||||
osrm::json::Array json_coord;
|
||||
json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
|
||||
source_coord_json_array.values.push_back(json_coord);
|
||||
}
|
||||
json_result.values["source_coordinates"] = source_coord_json_array;
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
};
|
||||
|
||||
#endif // DISTANCE_TABLE_HPP
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HELLO_WORLD_HPP
|
||||
#define HELLO_WORLD_HPP
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../util/json_renderer.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
class HelloWorldPlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::string temp_string;
|
||||
|
||||
public:
|
||||
HelloWorldPlugin() : descriptor_string("hello") {}
|
||||
virtual ~HelloWorldPlugin() {}
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
|
||||
Status HandleRequest(const RouteParameters &routeParameters,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
std::string temp_string;
|
||||
json_result.values["title"] = "Hello World";
|
||||
|
||||
temp_string = std::to_string(routeParameters.zoom_level);
|
||||
json_result.values["zoom_level"] = temp_string;
|
||||
|
||||
temp_string = std::to_string(routeParameters.check_sum);
|
||||
json_result.values["check_sum"] = temp_string;
|
||||
json_result.values["instructions"] = (routeParameters.print_instructions ? "yes" : "no");
|
||||
json_result.values["geometry"] = (routeParameters.geometry ? "yes" : "no");
|
||||
json_result.values["compression"] = (routeParameters.compression ? "yes" : "no");
|
||||
json_result.values["output_format"] =
|
||||
(!routeParameters.output_format.empty() ? "yes" : "no");
|
||||
|
||||
json_result.values["jsonp_parameter"] =
|
||||
(!routeParameters.jsonp_parameter.empty() ? "yes" : "no");
|
||||
json_result.values["language"] = (!routeParameters.language.empty() ? "yes" : "no");
|
||||
|
||||
temp_string = std::to_string(routeParameters.coordinates.size());
|
||||
json_result.values["location_count"] = temp_string;
|
||||
|
||||
osrm::json::Array json_locations;
|
||||
unsigned counter = 0;
|
||||
for (const FixedPointCoordinate &coordinate : routeParameters.coordinates)
|
||||
{
|
||||
osrm::json::Object json_location;
|
||||
osrm::json::Array json_coordinates;
|
||||
|
||||
json_coordinates.values.push_back(
|
||||
static_cast<double>(coordinate.lat / COORDINATE_PRECISION));
|
||||
json_coordinates.values.push_back(
|
||||
static_cast<double>(coordinate.lon / COORDINATE_PRECISION));
|
||||
json_location.values[std::to_string(counter)] = json_coordinates;
|
||||
json_locations.values.push_back(json_location);
|
||||
++counter;
|
||||
}
|
||||
json_result.values["locations"] = json_locations;
|
||||
json_result.values["hint_count"] = routeParameters.hints.size();
|
||||
|
||||
osrm::json::Array json_hints;
|
||||
counter = 0;
|
||||
for (const std::string ¤t_hint : routeParameters.hints)
|
||||
{
|
||||
json_hints.values.push_back(current_hint);
|
||||
++counter;
|
||||
}
|
||||
json_result.values["hints"] = json_hints;
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif // HELLO_WORLD_HPP
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MATCH_HPP
|
||||
#define MATCH_HPP
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../algorithms/bayes_classifier.hpp"
|
||||
#include "../algorithms/object_encoder.hpp"
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../descriptors/descriptor_base.hpp"
|
||||
#include "../descriptors/json_descriptor.hpp"
|
||||
#include "../routing_algorithms/map_matching.hpp"
|
||||
#include "../util/compute_angle.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/json_logger.hpp"
|
||||
#include "../util/json_util.hpp"
|
||||
#include "../util/string_util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
||||
{
|
||||
constexpr static const unsigned max_number_of_candidates = 10;
|
||||
|
||||
std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
|
||||
using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
|
||||
using TraceClassification = ClassifierT::ClassificationT;
|
||||
|
||||
public:
|
||||
MapMatchingPlugin(DataFacadeT *facade, const int max_locations_map_matching)
|
||||
: descriptor_string("match"), facade(facade),
|
||||
max_locations_map_matching(max_locations_map_matching),
|
||||
// the values where derived from fitting a laplace distribution
|
||||
// to the values of manually classified traces
|
||||
classifier(LaplaceDistribution(0.005986, 0.016646),
|
||||
LaplaceDistribution(0.054385, 0.458432),
|
||||
0.696774) // valid apriori probability
|
||||
{
|
||||
search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
|
||||
}
|
||||
|
||||
virtual ~MapMatchingPlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const final override { return descriptor_string; }
|
||||
|
||||
TraceClassification
|
||||
classify(const float trace_length, const float matched_length, const int removed_points) const
|
||||
{
|
||||
(void)removed_points; // unused
|
||||
|
||||
const double distance_feature = -std::log(trace_length) + std::log(matched_length);
|
||||
|
||||
// matched to the same point
|
||||
if (!std::isfinite(distance_feature))
|
||||
{
|
||||
return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
|
||||
}
|
||||
|
||||
const auto label_with_confidence = classifier.classify(distance_feature);
|
||||
|
||||
return label_with_confidence;
|
||||
}
|
||||
|
||||
osrm::matching::CandidateLists getCandidates(
|
||||
const std::vector<FixedPointCoordinate> &input_coords,
|
||||
const std::vector<std::pair<const int, const boost::optional<int>>> &input_bearings,
|
||||
const double gps_precision,
|
||||
std::vector<double> &sub_trace_lengths)
|
||||
{
|
||||
osrm::matching::CandidateLists candidates_lists;
|
||||
|
||||
double query_radius = 10 * gps_precision;
|
||||
double last_distance =
|
||||
coordinate_calculation::haversine_distance(input_coords[0], input_coords[1]);
|
||||
|
||||
sub_trace_lengths.resize(input_coords.size());
|
||||
sub_trace_lengths[0] = 0;
|
||||
for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size()))
|
||||
{
|
||||
bool allow_uturn = false;
|
||||
if (0 < current_coordinate)
|
||||
{
|
||||
last_distance = coordinate_calculation::haversine_distance(
|
||||
input_coords[current_coordinate - 1], input_coords[current_coordinate]);
|
||||
|
||||
sub_trace_lengths[current_coordinate] +=
|
||||
sub_trace_lengths[current_coordinate - 1] + last_distance;
|
||||
}
|
||||
|
||||
if (input_coords.size() - 1 > current_coordinate && 0 < current_coordinate)
|
||||
{
|
||||
double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
|
||||
input_coords[current_coordinate - 1], input_coords[current_coordinate],
|
||||
input_coords[current_coordinate + 1]);
|
||||
|
||||
// sharp turns indicate a possible uturn
|
||||
if (turn_angle <= 90.0 || turn_angle >= 270.0)
|
||||
{
|
||||
allow_uturn = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Use bearing values if supplied, otherwise fallback to 0,180 defaults
|
||||
auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate].first : 0;
|
||||
auto range = input_bearings.size() > 0
|
||||
? (input_bearings[current_coordinate].second
|
||||
? *input_bearings[current_coordinate].second
|
||||
: 10)
|
||||
: 180;
|
||||
auto candidates = facade->NearestPhantomNodesInRange(input_coords[current_coordinate],
|
||||
query_radius, bearing, range);
|
||||
|
||||
if (candidates.size() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// sort by foward id, then by reverse id and then by distance
|
||||
std::sort(
|
||||
candidates.begin(), candidates.end(),
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
|
||||
{
|
||||
return lhs.phantom_node.forward_node_id < rhs.phantom_node.forward_node_id ||
|
||||
(lhs.phantom_node.forward_node_id == rhs.phantom_node.forward_node_id &&
|
||||
(lhs.phantom_node.reverse_node_id < rhs.phantom_node.reverse_node_id ||
|
||||
(lhs.phantom_node.reverse_node_id ==
|
||||
rhs.phantom_node.reverse_node_id &&
|
||||
lhs.distance < rhs.distance)));
|
||||
});
|
||||
|
||||
auto new_end = std::unique(
|
||||
candidates.begin(), candidates.end(),
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
|
||||
{
|
||||
return lhs.phantom_node.forward_node_id == rhs.phantom_node.forward_node_id &&
|
||||
lhs.phantom_node.reverse_node_id == rhs.phantom_node.reverse_node_id;
|
||||
});
|
||||
candidates.resize(new_end - candidates.begin());
|
||||
|
||||
if (!allow_uturn)
|
||||
{
|
||||
const auto compact_size = candidates.size();
|
||||
for (const auto i : osrm::irange<std::size_t>(0, compact_size))
|
||||
{
|
||||
// Split edge if it is bidirectional and append reverse direction to end of list
|
||||
if (candidates[i].phantom_node.forward_node_id != SPECIAL_NODEID &&
|
||||
candidates[i].phantom_node.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
PhantomNode reverse_node(candidates[i].phantom_node);
|
||||
reverse_node.forward_node_id = SPECIAL_NODEID;
|
||||
candidates.push_back(
|
||||
PhantomNodeWithDistance{reverse_node, candidates[i].distance});
|
||||
|
||||
candidates[i].phantom_node.reverse_node_id = SPECIAL_NODEID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort by distance to make pruning effective
|
||||
std::sort(candidates.begin(), candidates.end(),
|
||||
[](const PhantomNodeWithDistance &lhs, const PhantomNodeWithDistance &rhs)
|
||||
{
|
||||
return lhs.distance < rhs.distance;
|
||||
});
|
||||
|
||||
candidates_lists.push_back(std::move(candidates));
|
||||
}
|
||||
|
||||
return candidates_lists;
|
||||
}
|
||||
|
||||
osrm::json::Object submatchingToJSON(const osrm::matching::SubMatching &sub,
|
||||
const RouteParameters &route_parameters,
|
||||
const InternalRouteResult &raw_route)
|
||||
{
|
||||
osrm::json::Object subtrace;
|
||||
|
||||
if (route_parameters.classify)
|
||||
{
|
||||
subtrace.values["confidence"] = sub.confidence;
|
||||
}
|
||||
|
||||
JSONDescriptor<DataFacadeT> json_descriptor(facade);
|
||||
json_descriptor.SetConfig(route_parameters);
|
||||
|
||||
subtrace.values["hint_data"] = json_descriptor.BuildHintData(raw_route);
|
||||
|
||||
if (route_parameters.geometry || route_parameters.print_instructions)
|
||||
{
|
||||
DescriptionFactory factory;
|
||||
FixedPointCoordinate current_coordinate;
|
||||
factory.SetStartSegment(raw_route.segment_end_coordinates.front().source_phantom,
|
||||
raw_route.source_traversed_in_reverse.front());
|
||||
for (const auto i :
|
||||
osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
|
||||
{
|
||||
for (const PathData &path_data : raw_route.unpacked_path_segments[i])
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(path_data.node);
|
||||
factory.AppendSegment(current_coordinate, path_data);
|
||||
}
|
||||
factory.SetEndSegment(raw_route.segment_end_coordinates[i].target_phantom,
|
||||
raw_route.target_traversed_in_reverse[i],
|
||||
raw_route.is_via_leg(i));
|
||||
}
|
||||
|
||||
factory.Run(route_parameters.zoom_level);
|
||||
|
||||
// we need because we don't run path simplification
|
||||
for (auto &segment : factory.path_description)
|
||||
{
|
||||
segment.necessary = true;
|
||||
}
|
||||
|
||||
if (route_parameters.geometry)
|
||||
{
|
||||
subtrace.values["geometry"] =
|
||||
factory.AppendGeometryString(route_parameters.compression);
|
||||
}
|
||||
|
||||
if (route_parameters.print_instructions)
|
||||
{
|
||||
std::vector<typename JSONDescriptor<DataFacadeT>::Segment> temp_segments;
|
||||
subtrace.values["instructions"] =
|
||||
json_descriptor.BuildTextualDescription(factory, temp_segments);
|
||||
}
|
||||
|
||||
factory.BuildRouteSummary(factory.get_entire_length(), raw_route.shortest_path_length);
|
||||
osrm::json::Object json_route_summary;
|
||||
json_route_summary.values["total_distance"] = factory.summary.distance;
|
||||
json_route_summary.values["total_time"] = factory.summary.duration;
|
||||
subtrace.values["route_summary"] = json_route_summary;
|
||||
}
|
||||
|
||||
subtrace.values["indices"] = osrm::json::make_array(sub.indices);
|
||||
|
||||
osrm::json::Array points;
|
||||
for (const auto &node : sub.nodes)
|
||||
{
|
||||
points.values.emplace_back(
|
||||
osrm::json::make_array(node.location.lat / COORDINATE_PRECISION,
|
||||
node.location.lon / COORDINATE_PRECISION));
|
||||
}
|
||||
subtrace.values["matched_points"] = points;
|
||||
|
||||
osrm::json::Array names;
|
||||
for (const auto &node : sub.nodes)
|
||||
{
|
||||
names.values.emplace_back(facade->get_name_for_id(node.name_id));
|
||||
}
|
||||
subtrace.values["matched_names"] = names;
|
||||
|
||||
return subtrace;
|
||||
}
|
||||
|
||||
Status HandleRequest(const RouteParameters &route_parameters,
|
||||
osrm::json::Object &json_result) final override
|
||||
{
|
||||
// enforce maximum number of locations for performance reasons
|
||||
if (max_locations_map_matching > 0 &&
|
||||
static_cast<int>(route_parameters.coordinates.size()) > max_locations_map_matching)
|
||||
{
|
||||
json_result.values["status_message"] = "Too many coodindates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
// check number of parameters
|
||||
if (!check_all_coordinates(route_parameters.coordinates))
|
||||
{
|
||||
json_result.values["status_message"] = "Invalid coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
std::vector<double> sub_trace_lengths;
|
||||
const auto &input_coords = route_parameters.coordinates;
|
||||
const auto &input_timestamps = route_parameters.timestamps;
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of timestamps does not match number of coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
if (input_bearings.size() > 0 && input_coords.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of bearings does not match number of coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
// enforce maximum number of locations for performance reasons
|
||||
if (static_cast<int>(input_coords.size()) < 2)
|
||||
{
|
||||
json_result.values["status_message"] = "At least two coordinates needed";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const auto candidates_lists = getCandidates(
|
||||
input_coords, input_bearings, route_parameters.gps_precision, sub_trace_lengths);
|
||||
if (candidates_lists.size() != input_coords.size())
|
||||
{
|
||||
BOOST_ASSERT(candidates_lists.size() < input_coords.size());
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segment for coordinate ") +
|
||||
std::to_string(candidates_lists.size());
|
||||
return Status::NoSegment;
|
||||
}
|
||||
|
||||
// setup logging if enabled
|
||||
if (osrm::json::Logger::get())
|
||||
osrm::json::Logger::get()->initialize("matching");
|
||||
|
||||
// call the actual map matching
|
||||
osrm::matching::SubMatchingList sub_matchings;
|
||||
search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps,
|
||||
route_parameters.matching_beta,
|
||||
route_parameters.gps_precision, sub_matchings);
|
||||
|
||||
osrm::json::Array matchings;
|
||||
for (auto &sub : sub_matchings)
|
||||
{
|
||||
// classify result
|
||||
if (route_parameters.classify)
|
||||
{
|
||||
double trace_length =
|
||||
sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
|
||||
TraceClassification classification =
|
||||
classify(trace_length, sub.length,
|
||||
(sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
|
||||
if (classification.first == ClassifierT::ClassLabel::POSITIVE)
|
||||
{
|
||||
sub.confidence = classification.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
sub.confidence = 1 - classification.second;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(sub.nodes.size() > 1);
|
||||
|
||||
// FIXME we only run this to obtain the geometry
|
||||
// The clean way would be to get this directly from the map matching plugin
|
||||
InternalRouteResult raw_route;
|
||||
PhantomNodes current_phantom_node_pair;
|
||||
for (unsigned i = 0; i < sub.nodes.size() - 1; ++i)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = sub.nodes[i];
|
||||
current_phantom_node_pair.target_phantom = sub.nodes[i + 1];
|
||||
BOOST_ASSERT(current_phantom_node_pair.source_phantom.is_valid());
|
||||
BOOST_ASSERT(current_phantom_node_pair.target_phantom.is_valid());
|
||||
raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
}
|
||||
search_engine_ptr->shortest_path(
|
||||
raw_route.segment_end_coordinates,
|
||||
std::vector<bool>(raw_route.segment_end_coordinates.size() + 1, true), raw_route);
|
||||
|
||||
BOOST_ASSERT(raw_route.shortest_path_length != INVALID_EDGE_WEIGHT);
|
||||
|
||||
matchings.values.emplace_back(submatchingToJSON(sub, route_parameters, raw_route));
|
||||
}
|
||||
|
||||
if (osrm::json::Logger::get())
|
||||
osrm::json::Logger::get()->render("matching", json_result);
|
||||
json_result.values["matchings"] = matchings;
|
||||
|
||||
if (sub_matchings.empty())
|
||||
{
|
||||
json_result.values["status_message"] = "Cannot find matchings";
|
||||
return Status::EmptyResult;
|
||||
}
|
||||
|
||||
json_result.values["status_message"] = "Found matchings";
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
int max_locations_map_matching;
|
||||
ClassifierT classifier;
|
||||
};
|
||||
|
||||
#endif // MATCH_HPP
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NEAREST_HPP
|
||||
#define NEAREST_HPP
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/json_renderer.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
|
||||
template <class DataFacadeT> class NearestPlugin final : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit NearestPlugin(DataFacadeT *facade) : facade(facade), descriptor_string("nearest") {}
|
||||
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
|
||||
Status HandleRequest(const RouteParameters &route_parameters,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
// check number of parameters
|
||||
if (route_parameters.coordinates.empty() ||
|
||||
!route_parameters.coordinates.front().is_valid())
|
||||
{
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_bearings.size() > 0 &&
|
||||
route_parameters.coordinates.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of bearings does not match number of coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
|
||||
const int bearing = input_bearings.size() > 0 ? input_bearings.front().first : 0;
|
||||
const int range =
|
||||
input_bearings.size() > 0
|
||||
? (input_bearings.front().second ? *input_bearings.front().second : 10)
|
||||
: 180;
|
||||
auto phantom_node_vector = facade->NearestPhantomNodes(route_parameters.coordinates.front(),
|
||||
number_of_results, bearing, range);
|
||||
|
||||
if (phantom_node_vector.empty())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segments for coordinate");
|
||||
return Status::NoSegment;
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["status_message"] = "Found nearest edge";
|
||||
if (number_of_results > 1)
|
||||
{
|
||||
osrm::json::Array results;
|
||||
|
||||
auto vector_length = phantom_node_vector.size();
|
||||
for (const auto i :
|
||||
osrm::irange<std::size_t>(0, std::min(number_of_results, vector_length)))
|
||||
{
|
||||
const auto &node = phantom_node_vector[i].phantom_node;
|
||||
osrm::json::Array json_coordinate;
|
||||
osrm::json::Object result;
|
||||
json_coordinate.values.push_back(node.location.lat / COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(node.location.lon / COORDINATE_PRECISION);
|
||||
result.values["mapped coordinate"] = json_coordinate;
|
||||
result.values["name"] = facade->get_name_for_id(node.name_id);
|
||||
results.values.push_back(result);
|
||||
}
|
||||
json_result.values["results"] = results;
|
||||
}
|
||||
else
|
||||
{
|
||||
osrm::json::Array json_coordinate;
|
||||
json_coordinate.values.push_back(
|
||||
phantom_node_vector.front().phantom_node.location.lat / COORDINATE_PRECISION);
|
||||
json_coordinate.values.push_back(
|
||||
phantom_node_vector.front().phantom_node.location.lon / COORDINATE_PRECISION);
|
||||
json_result.values["mapped_coordinate"] = json_coordinate;
|
||||
json_result.values["name"] =
|
||||
facade->get_name_for_id(phantom_node_vector.front().phantom_node.name_id);
|
||||
}
|
||||
}
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* NEAREST_HPP */
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BASE_PLUGIN_HPP
|
||||
#define BASE_PLUGIN_HPP
|
||||
|
||||
#include "../data_structures/phantom_node.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
#include <osrm/json_container.hpp>
|
||||
#include <osrm/route_parameters.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BasePlugin
|
||||
{
|
||||
public:
|
||||
enum class Status : int
|
||||
{
|
||||
Ok = 200,
|
||||
EmptyResult = 207,
|
||||
NoSegment = 208,
|
||||
Error = 400
|
||||
};
|
||||
|
||||
BasePlugin() {}
|
||||
// Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BasePlugin() {}
|
||||
virtual const std::string GetDescriptor() const = 0;
|
||||
virtual Status HandleRequest(const RouteParameters &, osrm::json::Object &) = 0;
|
||||
virtual bool check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates,
|
||||
const unsigned min = 2) const final
|
||||
{
|
||||
if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
|
||||
[](const FixedPointCoordinate &coordinate)
|
||||
{
|
||||
return !coordinate.is_valid();
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decides whether to use the phantom node from a big or small component if both are found.
|
||||
// Returns true if all phantom nodes are in the same component after snapping.
|
||||
std::vector<PhantomNode> snapPhantomNodes(
|
||||
const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
|
||||
{
|
||||
const auto check_component_id_is_tiny =
|
||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
{
|
||||
return phantom_pair.first.component.is_tiny;
|
||||
};
|
||||
|
||||
// are all phantoms from a tiny cc?
|
||||
const auto check_all_in_same_component =
|
||||
[](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
|
||||
{
|
||||
const auto component_id = nodes.front().first.component.id;
|
||||
|
||||
return std::all_of(std::begin(nodes), std::end(nodes),
|
||||
[component_id](const PhantomNodePair &phantom_pair)
|
||||
{
|
||||
return component_id == phantom_pair.first.component.id;
|
||||
});
|
||||
};
|
||||
|
||||
const auto fallback_to_big_component =
|
||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
{
|
||||
if (phantom_pair.first.component.is_tiny && phantom_pair.second.is_valid() &&
|
||||
!phantom_pair.second.component.is_tiny)
|
||||
{
|
||||
return phantom_pair.second;
|
||||
}
|
||||
return phantom_pair.first;
|
||||
};
|
||||
|
||||
const auto use_closed_phantom = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
{
|
||||
return phantom_pair.first;
|
||||
};
|
||||
|
||||
const bool every_phantom_is_in_tiny_cc =
|
||||
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
|
||||
check_component_id_is_tiny);
|
||||
auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
|
||||
|
||||
std::vector<PhantomNode> snapped_phantoms;
|
||||
snapped_phantoms.reserve(phantom_node_pair_list.size());
|
||||
|
||||
// The only case we don't snap to the big component if all phantoms are in the same small
|
||||
// component
|
||||
if (every_phantom_is_in_tiny_cc && all_in_same_component)
|
||||
{
|
||||
std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
|
||||
std::back_inserter(snapped_phantoms), use_closed_phantom);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
|
||||
std::back_inserter(snapped_phantoms), fallback_to_big_component);
|
||||
}
|
||||
|
||||
return snapped_phantoms;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BASE_PLUGIN_HPP */
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TIMESTAMP_PLUGIN_H
|
||||
#define TIMESTAMP_PLUGIN_H
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../util/json_renderer.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
template <class DataFacadeT> class TimestampPlugin final : public BasePlugin
|
||||
{
|
||||
public:
|
||||
explicit TimestampPlugin(const DataFacadeT *facade)
|
||||
: facade(facade), descriptor_string("timestamp")
|
||||
{
|
||||
}
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
Status HandleRequest(const RouteParameters &route_parameters,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
(void)route_parameters; // unused
|
||||
|
||||
const std::string timestamp = facade->GetTimestamp();
|
||||
json_result.values["timestamp"] = timestamp;
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
const DataFacadeT *facade;
|
||||
std::string descriptor_string;
|
||||
};
|
||||
|
||||
#endif /* TIMESTAMP_PLUGIN_H */
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TRIP_HPP
|
||||
#define TRIP_HPP
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../algorithms/object_encoder.hpp"
|
||||
#include "../algorithms/tarjan_scc.hpp"
|
||||
#include "../algorithms/trip_nearest_neighbour.hpp"
|
||||
#include "../algorithms/trip_farthest_insertion.hpp"
|
||||
#include "../algorithms/trip_brute_force.hpp"
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../data_structures/matrix_graph_wrapper.hpp" // wrapper to use tarjan
|
||||
// scc on dist table
|
||||
#include "../descriptors/descriptor_base.hpp" // to make json output
|
||||
#include "../descriptors/json_descriptor.hpp" // to make json output
|
||||
#include "../util/make_unique.hpp"
|
||||
#include "../util/timing_util.hpp" // to time runtime
|
||||
//#include "../util/simple_logger.hpp" // for logging output
|
||||
#include "../util/dist_table_wrapper.hpp" // to access the dist
|
||||
// table more easily
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
std::string descriptor_string;
|
||||
DataFacadeT *facade;
|
||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
int max_locations_trip;
|
||||
|
||||
public:
|
||||
explicit RoundTripPlugin(DataFacadeT *facade, int max_locations_trip)
|
||||
: descriptor_string("trip"), facade(facade), max_locations_trip(max_locations_trip)
|
||||
{
|
||||
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
|
||||
}
|
||||
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
|
||||
std::vector<PhantomNode> GetPhantomNodes(const RouteParameters &route_parameters)
|
||||
{
|
||||
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
|
||||
std::vector<PhantomNode> phantom_node_list;
|
||||
phantom_node_list.reserve(route_parameters.coordinates.size());
|
||||
|
||||
// find phantom nodes for all input coords
|
||||
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
|
||||
{
|
||||
// if client hints are helpful, encode hints
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
PhantomNode current_phantom_node;
|
||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
|
||||
if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
phantom_node_list.push_back(std::move(current_phantom_node));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
|
||||
const int range = input_bearings.size() > 0
|
||||
? (input_bearings[i].second ? *input_bearings[i].second : 10)
|
||||
: 180;
|
||||
auto results = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range);
|
||||
if (results.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
phantom_node_list.push_back(std::move(results.front().phantom_node));
|
||||
BOOST_ASSERT(phantom_node_list.back().is_valid(facade->GetNumberOfNodes()));
|
||||
}
|
||||
|
||||
return phantom_node_list;
|
||||
}
|
||||
|
||||
// Object to hold all strongly connected components (scc) of a graph
|
||||
// to access all graphs with component ID i, get the iterators by:
|
||||
// auto start = std::begin(scc_component.component) + scc_component.range[i];
|
||||
// auto end = std::begin(scc_component.component) + scc_component.range[i+1];
|
||||
struct SCC_Component
|
||||
{
|
||||
// in_component: all NodeIDs sorted by component ID
|
||||
// in_range: index where a new component starts
|
||||
//
|
||||
// example: NodeID 0, 1, 2, 4, 5 are in component 0
|
||||
// NodeID 3, 6, 7, 8 are in component 1
|
||||
// => in_component = [0, 1, 2, 4, 5, 3, 6, 7, 8]
|
||||
// => in_range = [0, 5]
|
||||
SCC_Component(std::vector<NodeID> in_component, std::vector<size_t> in_range)
|
||||
: component(std::move(in_component)), range(std::move(in_range))
|
||||
{
|
||||
range.push_back(component.size());
|
||||
|
||||
BOOST_ASSERT_MSG(component.size() >= range.size(),
|
||||
"scc component and its ranges do not match");
|
||||
BOOST_ASSERT_MSG(component.size() > 0, "there's no scc component");
|
||||
BOOST_ASSERT_MSG(*std::max_element(range.begin(), range.end()) <= component.size(),
|
||||
"scc component ranges are out of bound");
|
||||
BOOST_ASSERT_MSG(*std::min_element(range.begin(), range.end()) >= 0,
|
||||
"invalid scc component range");
|
||||
BOOST_ASSERT_MSG(std::is_sorted(std::begin(range), std::end(range)),
|
||||
"invalid component ranges");
|
||||
};
|
||||
|
||||
// constructor to use when whole graph is one single scc
|
||||
SCC_Component(std::vector<NodeID> in_component)
|
||||
: component(std::move(in_component)), range({0, component.size()}){};
|
||||
|
||||
std::size_t GetNumberOfComponents() const
|
||||
{
|
||||
BOOST_ASSERT_MSG(range.size() > 0, "there's no range");
|
||||
return range.size() - 1;
|
||||
}
|
||||
|
||||
const std::vector<NodeID> component;
|
||||
std::vector<std::size_t> range;
|
||||
};
|
||||
|
||||
// takes the number of locations and its distance matrix,
|
||||
// identifies and splits the graph in its strongly connected components (scc)
|
||||
// and returns an SCC_Component
|
||||
SCC_Component SplitUnaccessibleLocations(const std::size_t number_of_locations,
|
||||
const DistTableWrapper<EdgeWeight> &result_table)
|
||||
{
|
||||
|
||||
if (std::find(std::begin(result_table), std::end(result_table), INVALID_EDGE_WEIGHT) ==
|
||||
std::end(result_table))
|
||||
{
|
||||
// whole graph is one scc
|
||||
std::vector<NodeID> location_ids(number_of_locations);
|
||||
std::iota(std::begin(location_ids), std::end(location_ids), 0);
|
||||
return SCC_Component(std::move(location_ids));
|
||||
}
|
||||
|
||||
// Run TarjanSCC
|
||||
auto wrapper = std::make_shared<MatrixGraphWrapper<EdgeWeight>>(result_table.GetTable(),
|
||||
number_of_locations);
|
||||
auto scc = TarjanSCC<MatrixGraphWrapper<EdgeWeight>>(wrapper);
|
||||
scc.run();
|
||||
|
||||
const auto number_of_components = scc.get_number_of_components();
|
||||
|
||||
std::vector<std::size_t> range_insertion;
|
||||
std::vector<std::size_t> range;
|
||||
range_insertion.reserve(number_of_components);
|
||||
range.reserve(number_of_components);
|
||||
|
||||
std::vector<NodeID> components(number_of_locations, 0);
|
||||
|
||||
std::size_t prefix = 0;
|
||||
for (std::size_t j = 0; j < number_of_components; ++j)
|
||||
{
|
||||
range_insertion.push_back(prefix);
|
||||
range.push_back(prefix);
|
||||
prefix += scc.get_component_size(j);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < number_of_locations; ++i)
|
||||
{
|
||||
components[range_insertion[scc.get_component_id(i)]] = i;
|
||||
++range_insertion[scc.get_component_id(i)];
|
||||
}
|
||||
|
||||
return SCC_Component(std::move(components), std::move(range));
|
||||
}
|
||||
|
||||
void SetLocPermutationOutput(const std::vector<NodeID> &permutation,
|
||||
osrm::json::Object &json_result)
|
||||
{
|
||||
osrm::json::Array json_permutation;
|
||||
json_permutation.values.insert(std::end(json_permutation.values), std::begin(permutation),
|
||||
std::end(permutation));
|
||||
json_result.values["permutation"] = json_permutation;
|
||||
}
|
||||
|
||||
InternalRouteResult ComputeRoute(const std::vector<PhantomNode> &phantom_node_list,
|
||||
const RouteParameters &route_parameters,
|
||||
const std::vector<NodeID> &trip)
|
||||
{
|
||||
InternalRouteResult min_route;
|
||||
// given he final trip, compute total distance and return the route and location permutation
|
||||
PhantomNodes viapoint;
|
||||
const auto start = std::begin(trip);
|
||||
const auto end = std::end(trip);
|
||||
// computes a roundtrip from the nodes in trip
|
||||
for (auto it = start; it != end; ++it)
|
||||
{
|
||||
const auto from_node = *it;
|
||||
// if from_node is the last node, compute the route from the last to the first location
|
||||
const auto to_node = std::next(it) != end ? *std::next(it) : *start;
|
||||
|
||||
viapoint = PhantomNodes{phantom_node_list[from_node], phantom_node_list[to_node]};
|
||||
min_route.segment_end_coordinates.emplace_back(viapoint);
|
||||
}
|
||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
|
||||
|
||||
std::vector<bool> uturns(trip.size() + 1);
|
||||
std::transform(trip.begin(), trip.end(), uturns.begin(),
|
||||
[&route_parameters](const NodeID idx)
|
||||
{
|
||||
return route_parameters.uturns[idx];
|
||||
});
|
||||
uturns.back() = route_parameters.uturns[trip.front()];
|
||||
|
||||
search_engine_ptr->shortest_path(min_route.segment_end_coordinates, uturns, min_route);
|
||||
|
||||
BOOST_ASSERT_MSG(min_route.shortest_path_length < INVALID_EDGE_WEIGHT, "unroutable route");
|
||||
return min_route;
|
||||
}
|
||||
|
||||
Status HandleRequest(const RouteParameters &route_parameters,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
if (max_locations_trip > 0 &&
|
||||
(static_cast<int>(route_parameters.coordinates.size()) > max_locations_trip))
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of entries " + std::to_string(route_parameters.coordinates.size()) +
|
||||
" is higher than current maximum (" + std::to_string(max_locations_trip) + ")";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
// check if all inputs are coordinates
|
||||
if (!check_all_coordinates(route_parameters.coordinates))
|
||||
{
|
||||
json_result.values["status_message"] = "Invalid coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_bearings.size() > 0 &&
|
||||
route_parameters.coordinates.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of bearings does not match number of coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
// get phantom nodes
|
||||
auto phantom_node_list = GetPhantomNodes(route_parameters);
|
||||
if (phantom_node_list.size() != route_parameters.coordinates.size())
|
||||
{
|
||||
BOOST_ASSERT(phantom_node_list.size() < route_parameters.coordinates.size());
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segment for coordinate ") +
|
||||
std::to_string(phantom_node_list.size());
|
||||
return Status::NoSegment;
|
||||
}
|
||||
|
||||
const auto number_of_locations = phantom_node_list.size();
|
||||
|
||||
// compute the distance table of all phantom nodes
|
||||
const auto result_table = DistTableWrapper<EdgeWeight>(
|
||||
*search_engine_ptr->distance_table(phantom_node_list, phantom_node_list),
|
||||
number_of_locations);
|
||||
|
||||
if (result_table.size() == 0)
|
||||
{
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const constexpr std::size_t BF_MAX_FEASABLE = 10;
|
||||
BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
|
||||
"Distance Table has wrong size");
|
||||
|
||||
// get scc components
|
||||
SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);
|
||||
|
||||
using NodeIDIterator = typename std::vector<NodeID>::const_iterator;
|
||||
|
||||
std::vector<std::vector<NodeID>> route_result;
|
||||
route_result.reserve(scc.GetNumberOfComponents());
|
||||
TIMER_START(TRIP_TIMER);
|
||||
// run Trip computation for every SCC
|
||||
for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
|
||||
{
|
||||
const auto component_size = scc.range[k + 1] - scc.range[k];
|
||||
|
||||
BOOST_ASSERT_MSG(component_size >= 0, "invalid component size");
|
||||
|
||||
if (component_size > 1)
|
||||
{
|
||||
std::vector<NodeID> scc_route;
|
||||
NodeIDIterator start = std::begin(scc.component) + scc.range[k];
|
||||
NodeIDIterator end = std::begin(scc.component) + scc.range[k + 1];
|
||||
|
||||
if (component_size < BF_MAX_FEASABLE)
|
||||
{
|
||||
scc_route =
|
||||
osrm::trip::BruteForceTrip(start, end, number_of_locations, result_table);
|
||||
}
|
||||
else
|
||||
{
|
||||
scc_route = osrm::trip::FarthestInsertionTrip(start, end, number_of_locations,
|
||||
result_table);
|
||||
}
|
||||
|
||||
// use this output if debugging of route is needed:
|
||||
// SimpleLogger().Write() << "Route #" << k << ": " << [&scc_route]()
|
||||
// {
|
||||
// std::string s = "";
|
||||
// for (auto x : scc_route)
|
||||
// {
|
||||
// s += std::to_string(x) + " ";
|
||||
// }
|
||||
// return s;
|
||||
// }();
|
||||
|
||||
route_result.push_back(std::move(scc_route));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if component only consists of one node, add it to the result routes
|
||||
route_result.emplace_back(scc.component[scc.range[k]]);
|
||||
}
|
||||
}
|
||||
|
||||
// compute all round trip routes
|
||||
std::vector<InternalRouteResult> comp_route;
|
||||
comp_route.reserve(route_result.size());
|
||||
for (auto &elem : route_result)
|
||||
{
|
||||
comp_route.push_back(ComputeRoute(phantom_node_list, route_parameters, elem));
|
||||
}
|
||||
|
||||
TIMER_STOP(TRIP_TIMER);
|
||||
|
||||
// prepare JSON output
|
||||
// create a json object for every trip
|
||||
osrm::json::Array trip;
|
||||
for (std::size_t i = 0; i < route_result.size(); ++i)
|
||||
{
|
||||
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor =
|
||||
osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
|
||||
descriptor->SetConfig(route_parameters);
|
||||
|
||||
osrm::json::Object scc_trip;
|
||||
|
||||
// set permutation output
|
||||
SetLocPermutationOutput(route_result[i], scc_trip);
|
||||
// set viaroute output
|
||||
descriptor->Run(comp_route[i], scc_trip);
|
||||
|
||||
trip.values.push_back(std::move(scc_trip));
|
||||
}
|
||||
|
||||
|
||||
if (trip.values.empty())
|
||||
{
|
||||
json_result.values["status_message"] = "Cannot find trips";
|
||||
return Status::EmptyResult;
|
||||
}
|
||||
|
||||
json_result.values["trips"] = std::move(trip);
|
||||
json_result.values["status_message"] = "Found trips";
|
||||
return Status::Ok;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TRIP_HPP
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIA_ROUTE_HPP
|
||||
#define VIA_ROUTE_HPP
|
||||
|
||||
#include "plugin_base.hpp"
|
||||
|
||||
#include "../algorithms/object_encoder.hpp"
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../descriptors/descriptor_base.hpp"
|
||||
#include "../descriptors/gpx_descriptor.hpp"
|
||||
#include "../descriptors/json_descriptor.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/json_renderer.hpp"
|
||||
#include "../util/make_unique.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
DescriptorTable descriptor_table;
|
||||
std::string descriptor_string;
|
||||
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
|
||||
DataFacadeT *facade;
|
||||
int max_locations_viaroute;
|
||||
|
||||
public:
|
||||
explicit ViaRoutePlugin(DataFacadeT *facade, int max_locations_viaroute)
|
||||
: descriptor_string("viaroute"), facade(facade),
|
||||
max_locations_viaroute(max_locations_viaroute)
|
||||
{
|
||||
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
|
||||
|
||||
descriptor_table.emplace("json", 0);
|
||||
descriptor_table.emplace("gpx", 1);
|
||||
// descriptor_table.emplace("geojson", 2);
|
||||
}
|
||||
|
||||
virtual ~ViaRoutePlugin() {}
|
||||
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
|
||||
Status HandleRequest(const RouteParameters &route_parameters,
|
||||
osrm::json::Object &json_result) override final
|
||||
{
|
||||
if (max_locations_viaroute > 0 &&
|
||||
(static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of entries " + std::to_string(route_parameters.coordinates.size()) +
|
||||
" is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
if (!check_all_coordinates(route_parameters.coordinates))
|
||||
{
|
||||
json_result.values["status_message"] = "Invalid coordinates";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_bearings.size() > 0 &&
|
||||
route_parameters.coordinates.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
"Number of bearings does not match number of coordinate";
|
||||
return Status::Error;
|
||||
}
|
||||
|
||||
std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size());
|
||||
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
|
||||
|
||||
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
|
||||
{
|
||||
if (checksum_OK && i < route_parameters.hints.size() &&
|
||||
!route_parameters.hints[i].empty())
|
||||
{
|
||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
|
||||
phantom_node_pair_list[i].first);
|
||||
if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
|
||||
const int range = input_bearings.size() > 0
|
||||
? (input_bearings[i].second ? *input_bearings[i].second : 10)
|
||||
: 180;
|
||||
phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
route_parameters.coordinates[i], bearing, range);
|
||||
// we didn't found a fitting node, return error
|
||||
if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segment for coordinate ") +
|
||||
std::to_string(i);
|
||||
return Status::NoSegment;
|
||||
}
|
||||
BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()));
|
||||
BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes()));
|
||||
}
|
||||
|
||||
auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
|
||||
|
||||
InternalRouteResult raw_route;
|
||||
auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
|
||||
const PhantomNode &second_node)
|
||||
{
|
||||
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
|
||||
};
|
||||
osrm::for_each_pair(snapped_phantoms, build_phantom_pairs);
|
||||
|
||||
if (1 == raw_route.segment_end_coordinates.size())
|
||||
{
|
||||
if (route_parameters.alternate_route)
|
||||
{
|
||||
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
|
||||
raw_route);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
|
||||
route_parameters.uturns, raw_route);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
|
||||
route_parameters.uturns, raw_route);
|
||||
}
|
||||
|
||||
bool no_route = INVALID_EDGE_WEIGHT == raw_route.shortest_path_length;
|
||||
|
||||
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
|
||||
switch (descriptor_table.get_id(route_parameters.output_format))
|
||||
{
|
||||
case 1:
|
||||
descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
// case 2:
|
||||
// descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
|
||||
// break;
|
||||
default:
|
||||
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
|
||||
break;
|
||||
}
|
||||
|
||||
descriptor->SetConfig(route_parameters);
|
||||
descriptor->Run(raw_route, json_result);
|
||||
|
||||
// we can only know this after the fact, different SCC ids still
|
||||
// allow for connection in one direction.
|
||||
if (no_route)
|
||||
{
|
||||
auto first_component_id = snapped_phantoms.front().component.id;
|
||||
auto not_in_same_component =
|
||||
std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
|
||||
[first_component_id](const PhantomNode &node)
|
||||
{
|
||||
return node.component.id != first_component_id;
|
||||
});
|
||||
if (not_in_same_component)
|
||||
{
|
||||
json_result.values["status_message"] = "Impossible route between points";
|
||||
return Status::EmptyResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json_result.values["status_message"] = "Found route between points";
|
||||
}
|
||||
|
||||
return Status::Ok;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // VIA_ROUTE_HPP
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef POLYLINECOMPRESSOR_H_
|
||||
#define POLYLINECOMPRESSOR_H_
|
||||
|
||||
struct SegmentInformation;
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class PolylineCompressor
|
||||
{
|
||||
private:
|
||||
std::string encode_vector(std::vector<int> &numbers) const;
|
||||
|
||||
std::string encode_number(const int number_to_encode) const;
|
||||
|
||||
public:
|
||||
std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
std::vector<FixedPointCoordinate> decode_string(const std::string &geometry_string) const;
|
||||
};
|
||||
|
||||
#endif /* POLYLINECOMPRESSOR_H_ */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef POLYLINE_FORMATTER_HPP
|
||||
#define POLYLINE_FORMATTER_HPP
|
||||
|
||||
struct SegmentInformation;
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct PolylineFormatter
|
||||
{
|
||||
osrm::json::String printEncodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
|
||||
osrm::json::Array printUnencodedString(const std::vector<SegmentInformation> &polyline) const;
|
||||
};
|
||||
|
||||
#endif /* POLYLINE_FORMATTER_HPP */
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACT_ROUTE_NAMES_H
|
||||
#define EXTRACT_ROUTE_NAMES_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct RouteNames
|
||||
{
|
||||
std::string shortest_path_name_1;
|
||||
std::string shortest_path_name_2;
|
||||
std::string alternative_path_name_1;
|
||||
std::string alternative_path_name_2;
|
||||
};
|
||||
|
||||
// construct routes names
|
||||
template <class DataFacadeT, class SegmentT> struct ExtractRouteNames
|
||||
{
|
||||
private:
|
||||
SegmentT PickNextLongestSegment(const std::vector<SegmentT> &segment_list,
|
||||
const unsigned blocked_name_id) const
|
||||
{
|
||||
SegmentT result_segment;
|
||||
result_segment.length = 0;
|
||||
|
||||
for (const SegmentT &segment : segment_list)
|
||||
{
|
||||
if (segment.name_id != blocked_name_id && segment.length > result_segment.length &&
|
||||
segment.name_id != 0)
|
||||
{
|
||||
result_segment = segment;
|
||||
}
|
||||
}
|
||||
return result_segment;
|
||||
}
|
||||
|
||||
public:
|
||||
RouteNames operator()(std::vector<SegmentT> &shortest_path_segments,
|
||||
std::vector<SegmentT> &alternative_path_segments,
|
||||
const DataFacadeT *facade) const
|
||||
{
|
||||
RouteNames route_names;
|
||||
|
||||
SegmentT shortest_segment_1, shortest_segment_2;
|
||||
SegmentT alternative_segment_1, alternative_segment_2;
|
||||
|
||||
auto length_comperator = [](const SegmentT &a, const SegmentT &b)
|
||||
{
|
||||
return a.length > b.length;
|
||||
};
|
||||
auto name_id_comperator = [](const SegmentT &a, const SegmentT &b)
|
||||
{
|
||||
return a.name_id < b.name_id;
|
||||
};
|
||||
|
||||
if (shortest_path_segments.empty())
|
||||
{
|
||||
return route_names;
|
||||
}
|
||||
|
||||
// pick the longest segment for the shortest path.
|
||||
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), length_comperator);
|
||||
shortest_segment_1 = shortest_path_segments[0];
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
|
||||
length_comperator);
|
||||
|
||||
// also pick the longest segment for the alternative path
|
||||
alternative_segment_1 = alternative_path_segments[0];
|
||||
}
|
||||
|
||||
// compute the set difference (for shortest path) depending on names between shortest and
|
||||
// alternative
|
||||
std::vector<SegmentT> shortest_path_set_difference(shortest_path_segments.size());
|
||||
std::sort(shortest_path_segments.begin(), shortest_path_segments.end(), name_id_comperator);
|
||||
std::sort(alternative_path_segments.begin(), alternative_path_segments.end(),
|
||||
name_id_comperator);
|
||||
std::set_difference(shortest_path_segments.begin(), shortest_path_segments.end(),
|
||||
alternative_path_segments.begin(), alternative_path_segments.end(),
|
||||
shortest_path_set_difference.begin(), name_id_comperator);
|
||||
|
||||
std::sort(shortest_path_set_difference.begin(), shortest_path_set_difference.end(),
|
||||
length_comperator);
|
||||
shortest_segment_2 =
|
||||
PickNextLongestSegment(shortest_path_set_difference, shortest_segment_1.name_id);
|
||||
|
||||
// compute the set difference (for alternative path) depending on names between shortest and
|
||||
// alternative
|
||||
// vectors are still sorted, no need to do again
|
||||
BOOST_ASSERT(std::is_sorted(shortest_path_segments.begin(), shortest_path_segments.end(),
|
||||
name_id_comperator));
|
||||
BOOST_ASSERT(std::is_sorted(alternative_path_segments.begin(),
|
||||
alternative_path_segments.end(), name_id_comperator));
|
||||
|
||||
std::vector<SegmentT> alternative_path_set_difference(alternative_path_segments.size());
|
||||
std::set_difference(alternative_path_segments.begin(), alternative_path_segments.end(),
|
||||
shortest_path_segments.begin(), shortest_path_segments.end(),
|
||||
alternative_path_set_difference.begin(), name_id_comperator);
|
||||
|
||||
std::sort(alternative_path_set_difference.begin(), alternative_path_set_difference.end(),
|
||||
length_comperator);
|
||||
|
||||
if (!alternative_path_segments.empty())
|
||||
{
|
||||
alternative_segment_2 = PickNextLongestSegment(alternative_path_set_difference,
|
||||
alternative_segment_1.name_id);
|
||||
}
|
||||
|
||||
// move the segments into the order in which they occur.
|
||||
if (shortest_segment_1.position > shortest_segment_2.position)
|
||||
{
|
||||
std::swap(shortest_segment_1, shortest_segment_2);
|
||||
}
|
||||
if (alternative_segment_1.position > alternative_segment_2.position)
|
||||
{
|
||||
std::swap(alternative_segment_1, alternative_segment_2);
|
||||
}
|
||||
|
||||
// fetching names for the selected segments
|
||||
route_names.shortest_path_name_1 = facade->get_name_for_id(shortest_segment_1.name_id);
|
||||
route_names.shortest_path_name_2 = facade->get_name_for_id(shortest_segment_2.name_id);
|
||||
|
||||
route_names.alternative_path_name_1 =
|
||||
facade->get_name_for_id(alternative_segment_1.name_id);
|
||||
route_names.alternative_path_name_2 =
|
||||
facade->get_name_for_id(alternative_segment_2.name_id);
|
||||
|
||||
return route_names;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXTRACT_ROUTE_NAMES_H
|
||||
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ALTERNATIVE_PATH_ROUTING_HPP
|
||||
#define ALTERNATIVE_PATH_ROUTING_HPP
|
||||
|
||||
#include "routing_base.hpp"
|
||||
#include "../data_structures/search_engine_data.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/container.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <vector>
|
||||
|
||||
const double VIAPATH_ALPHA = 0.10;
|
||||
const double VIAPATH_EPSILON = 0.15; // alternative at most 15% longer
|
||||
const double VIAPATH_GAMMA = 0.75; // alternative shares at most 75% with the shortest.
|
||||
|
||||
template <class DataFacadeT>
|
||||
class AlternativeRouting final
|
||||
: private BasicRoutingInterface<DataFacadeT, AlternativeRouting<DataFacadeT>>
|
||||
{
|
||||
using super = BasicRoutingInterface<DataFacadeT, AlternativeRouting<DataFacadeT>>;
|
||||
using EdgeData = typename DataFacadeT::EdgeData;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
using SearchSpaceEdge = std::pair<NodeID, NodeID>;
|
||||
|
||||
struct RankedCandidateNode
|
||||
{
|
||||
RankedCandidateNode(const NodeID node, const int length, const int sharing)
|
||||
: node(node), length(length), sharing(sharing)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID node;
|
||||
int length;
|
||||
int sharing;
|
||||
|
||||
bool operator<(const RankedCandidateNode &other) const
|
||||
{
|
||||
return (2 * length + sharing) < (2 * other.length + other.sharing);
|
||||
}
|
||||
};
|
||||
DataFacadeT *facade;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
public:
|
||||
AlternativeRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), facade(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~AlternativeRouting() {}
|
||||
|
||||
void operator()(const PhantomNodes &phantom_node_pair, InternalRouteResult &raw_route_data)
|
||||
{
|
||||
std::vector<NodeID> alternative_path;
|
||||
std::vector<NodeID> via_node_candidate_list;
|
||||
std::vector<SearchSpaceEdge> forward_search_space;
|
||||
std::vector<SearchSpaceEdge> reverse_search_space;
|
||||
|
||||
// Init queues, semi-expensive because access to TSS invokes a sys-call
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &forward_heap1 = *(engine_working_data.forward_heap_1);
|
||||
QueryHeap &reverse_heap1 = *(engine_working_data.reverse_heap_1);
|
||||
QueryHeap &forward_heap2 = *(engine_working_data.forward_heap_2);
|
||||
QueryHeap &reverse_heap2 = *(engine_working_data.reverse_heap_2);
|
||||
|
||||
int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
const EdgeWeight min_edge_offset =
|
||||
std::min(-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
|
||||
|
||||
if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd-a insert: " <<
|
||||
// phantom_node_pair.source_phantom.forward_node_id << ", w: " <<
|
||||
// -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset();
|
||||
forward_heap1.Insert(phantom_node_pair.source_phantom.forward_node_id,
|
||||
-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.forward_node_id);
|
||||
}
|
||||
if (phantom_node_pair.source_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd-b insert: " <<
|
||||
// phantom_node_pair.source_phantom.reverse_node_id << ", w: " <<
|
||||
// -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset();
|
||||
forward_heap1.Insert(phantom_node_pair.source_phantom.reverse_node_id,
|
||||
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.source_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
if (phantom_node_pair.target_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
// SimpleLogger().Write(logDEBUG) << "rev-a insert: " <<
|
||||
// phantom_node_pair.target_phantom.forward_node_id << ", w: " <<
|
||||
// phantom_node_pair.target_phantom.GetForwardWeightPlusOffset();
|
||||
reverse_heap1.Insert(phantom_node_pair.target_phantom.forward_node_id,
|
||||
phantom_node_pair.target_phantom.GetForwardWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.forward_node_id);
|
||||
}
|
||||
if (phantom_node_pair.target_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
// SimpleLogger().Write(logDEBUG) << "rev-b insert: " <<
|
||||
// phantom_node_pair.target_phantom.reverse_node_id << ", w: " <<
|
||||
// phantom_node_pair.target_phantom.GetReverseWeightPlusOffset();
|
||||
reverse_heap1.Insert(phantom_node_pair.target_phantom.reverse_node_id,
|
||||
phantom_node_pair.target_phantom.GetReverseWeightPlusOffset(),
|
||||
phantom_node_pair.target_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||
{
|
||||
if (0 < forward_heap1.Size())
|
||||
{
|
||||
AlternativeRoutingStep<true>(forward_heap1, reverse_heap1, &middle_node,
|
||||
&upper_bound_to_shortest_path_distance,
|
||||
via_node_candidate_list, forward_search_space,
|
||||
min_edge_offset);
|
||||
}
|
||||
if (0 < reverse_heap1.Size())
|
||||
{
|
||||
AlternativeRoutingStep<false>(forward_heap1, reverse_heap1, &middle_node,
|
||||
&upper_bound_to_shortest_path_distance,
|
||||
via_node_candidate_list, reverse_search_space,
|
||||
min_edge_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_to_shortest_path_distance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
osrm::sort_unique_resize(via_node_candidate_list);
|
||||
|
||||
std::vector<NodeID> packed_forward_path;
|
||||
std::vector<NodeID> packed_reverse_path;
|
||||
|
||||
super::RetrievePackedPathFromSingleHeap(forward_heap1, middle_node, packed_forward_path);
|
||||
super::RetrievePackedPathFromSingleHeap(reverse_heap1, middle_node, packed_reverse_path);
|
||||
|
||||
// this set is is used as an indicator if a node is on the shortest path
|
||||
std::unordered_set<NodeID> nodes_in_path(packed_forward_path.size() +
|
||||
packed_reverse_path.size());
|
||||
nodes_in_path.insert(packed_forward_path.begin(), packed_forward_path.end());
|
||||
nodes_in_path.insert(middle_node);
|
||||
nodes_in_path.insert(packed_reverse_path.begin(), packed_reverse_path.end());
|
||||
|
||||
std::unordered_map<NodeID, int> approximated_forward_sharing;
|
||||
std::unordered_map<NodeID, int> approximated_reverse_sharing;
|
||||
|
||||
// sweep over search space, compute forward sharing for each current edge (u,v)
|
||||
for (const SearchSpaceEdge ¤t_edge : forward_search_space)
|
||||
{
|
||||
const NodeID u = current_edge.first;
|
||||
const NodeID v = current_edge.second;
|
||||
|
||||
if (nodes_in_path.find(v) != nodes_in_path.end())
|
||||
{
|
||||
// current_edge is on shortest path => sharing(v):=queue.GetKey(v);
|
||||
approximated_forward_sharing.emplace(v, forward_heap1.GetKey(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
// current edge is not on shortest path. Check if we know a value for the other
|
||||
// endpoint
|
||||
const auto sharing_of_u_iterator = approximated_forward_sharing.find(u);
|
||||
if (sharing_of_u_iterator != approximated_forward_sharing.end())
|
||||
{
|
||||
approximated_forward_sharing.emplace(v, sharing_of_u_iterator->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sweep over search space, compute backward sharing
|
||||
for (const SearchSpaceEdge ¤t_edge : reverse_search_space)
|
||||
{
|
||||
const NodeID u = current_edge.first;
|
||||
const NodeID v = current_edge.second;
|
||||
if (nodes_in_path.find(v) != nodes_in_path.end())
|
||||
{
|
||||
// current_edge is on shortest path => sharing(u):=queue.GetKey(u);
|
||||
approximated_reverse_sharing.emplace(v, reverse_heap1.GetKey(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
// current edge is not on shortest path. Check if we know a value for the other
|
||||
// endpoint
|
||||
const auto sharing_of_u_iterator = approximated_reverse_sharing.find(u);
|
||||
if (sharing_of_u_iterator != approximated_reverse_sharing.end())
|
||||
{
|
||||
approximated_reverse_sharing.emplace(v, sharing_of_u_iterator->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SimpleLogger().Write(logDEBUG) << "fwd_search_space size: " <<
|
||||
// forward_search_space.size() << ", marked " << approximated_forward_sharing.size() << "
|
||||
// nodes";
|
||||
// SimpleLogger().Write(logDEBUG) << "rev_search_space size: " <<
|
||||
// reverse_search_space.size() << ", marked " << approximated_reverse_sharing.size() << "
|
||||
// nodes";
|
||||
|
||||
std::vector<NodeID> preselected_node_list;
|
||||
for (const NodeID node : via_node_candidate_list)
|
||||
{
|
||||
const auto fwd_iterator = approximated_forward_sharing.find(node);
|
||||
const int fwd_sharing =
|
||||
(fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0;
|
||||
const auto rev_iterator = approximated_reverse_sharing.find(node);
|
||||
const int rev_sharing =
|
||||
(rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0;
|
||||
|
||||
const int approximated_sharing = fwd_sharing + rev_sharing;
|
||||
const int approximated_length = forward_heap1.GetKey(node) + reverse_heap1.GetKey(node);
|
||||
const bool length_passes =
|
||||
(approximated_length <
|
||||
upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON));
|
||||
const bool sharing_passes =
|
||||
(approximated_sharing <= upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
|
||||
const bool stretch_passes =
|
||||
(approximated_length - approximated_sharing) <
|
||||
((1. + VIAPATH_ALPHA) *
|
||||
(upper_bound_to_shortest_path_distance - approximated_sharing));
|
||||
|
||||
if (length_passes && sharing_passes && stretch_passes)
|
||||
{
|
||||
preselected_node_list.emplace_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NodeID> &packed_shortest_path = packed_forward_path;
|
||||
std::reverse(packed_shortest_path.begin(), packed_shortest_path.end());
|
||||
packed_shortest_path.emplace_back(middle_node);
|
||||
packed_shortest_path.insert(packed_shortest_path.end(), packed_reverse_path.begin(),
|
||||
packed_reverse_path.end());
|
||||
std::vector<RankedCandidateNode> ranked_candidates_list;
|
||||
|
||||
// prioritizing via nodes for deep inspection
|
||||
for (const NodeID node : preselected_node_list)
|
||||
{
|
||||
int length_of_via_path = 0, sharing_of_via_path = 0;
|
||||
ComputeLengthAndSharingOfViaPath(node, &length_of_via_path, &sharing_of_via_path,
|
||||
packed_shortest_path, min_edge_offset);
|
||||
const int maximum_allowed_sharing =
|
||||
static_cast<int>(upper_bound_to_shortest_path_distance * VIAPATH_GAMMA);
|
||||
if (sharing_of_via_path <= maximum_allowed_sharing &&
|
||||
length_of_via_path <= upper_bound_to_shortest_path_distance * (1 + VIAPATH_EPSILON))
|
||||
{
|
||||
ranked_candidates_list.emplace_back(node, length_of_via_path, sharing_of_via_path);
|
||||
}
|
||||
}
|
||||
std::sort(ranked_candidates_list.begin(), ranked_candidates_list.end());
|
||||
|
||||
NodeID selected_via_node = SPECIAL_NODEID;
|
||||
int length_of_via_path = INVALID_EDGE_WEIGHT;
|
||||
NodeID s_v_middle = SPECIAL_NODEID, v_t_middle = SPECIAL_NODEID;
|
||||
for (const RankedCandidateNode &candidate : ranked_candidates_list)
|
||||
{
|
||||
if (ViaNodeCandidatePassesTTest(
|
||||
forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, candidate,
|
||||
upper_bound_to_shortest_path_distance, &length_of_via_path, &s_v_middle,
|
||||
&v_t_middle, min_edge_offset))
|
||||
{
|
||||
// select first admissable
|
||||
selected_via_node = candidate.node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Unpack shortest path and alternative, if they exist
|
||||
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_distance)
|
||||
{
|
||||
BOOST_ASSERT(!packed_shortest_path.empty());
|
||||
raw_route_data.unpacked_path_segments.resize(1);
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(packed_shortest_path.front() != phantom_node_pair.source_phantom.forward_node_id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_node_id));
|
||||
|
||||
super::UnpackPath(
|
||||
// -- packed input
|
||||
packed_shortest_path.begin(), packed_shortest_path.end(),
|
||||
// -- start of route
|
||||
phantom_node_pair,
|
||||
// -- unpacked output
|
||||
raw_route_data.unpacked_path_segments.front());
|
||||
raw_route_data.shortest_path_length = upper_bound_to_shortest_path_distance;
|
||||
}
|
||||
|
||||
if (SPECIAL_NODEID != selected_via_node)
|
||||
{
|
||||
std::vector<NodeID> packed_alternate_path;
|
||||
// retrieve alternate path
|
||||
RetrievePackedAlternatePath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2,
|
||||
s_v_middle, v_t_middle, packed_alternate_path);
|
||||
|
||||
raw_route_data.alt_source_traversed_in_reverse.push_back((
|
||||
packed_alternate_path.front() != phantom_node_pair.source_phantom.forward_node_id));
|
||||
raw_route_data.alt_target_traversed_in_reverse.push_back(
|
||||
(packed_alternate_path.back() != phantom_node_pair.target_phantom.forward_node_id));
|
||||
|
||||
// unpack the alternate path
|
||||
super::UnpackPath(packed_alternate_path.begin(), packed_alternate_path.end(),
|
||||
phantom_node_pair, raw_route_data.unpacked_alternative);
|
||||
|
||||
raw_route_data.alternative_path_length = length_of_via_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(raw_route_data.alternative_path_length == INVALID_EDGE_WEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// unpack alternate <s,..,v,..,t> by exploring search spaces from v
|
||||
void RetrievePackedAlternatePath(const QueryHeap &forward_heap1,
|
||||
const QueryHeap &reverse_heap1,
|
||||
const QueryHeap &forward_heap2,
|
||||
const QueryHeap &reverse_heap2,
|
||||
const NodeID s_v_middle,
|
||||
const NodeID v_t_middle,
|
||||
std::vector<NodeID> &packed_path) const
|
||||
{
|
||||
// fetch packed path [s,v)
|
||||
std::vector<NodeID> packed_v_t_path;
|
||||
super::RetrievePackedPathFromHeap(forward_heap1, reverse_heap2, s_v_middle, packed_path);
|
||||
packed_path.pop_back(); // remove middle node. It's in both half-paths
|
||||
|
||||
// fetch patched path [v,t]
|
||||
super::RetrievePackedPathFromHeap(forward_heap2, reverse_heap1, v_t_middle,
|
||||
packed_v_t_path);
|
||||
|
||||
packed_path.insert(packed_path.end(), packed_v_t_path.begin(), packed_v_t_path.end());
|
||||
}
|
||||
|
||||
// TODO: reorder parameters
|
||||
// compute and unpack <s,..,v> and <v,..,t> by exploring search spaces
|
||||
// from v and intersecting against queues. only half-searches have to be
|
||||
// done at this stage
|
||||
void ComputeLengthAndSharingOfViaPath(const NodeID via_node,
|
||||
int *real_length_of_via_path,
|
||||
int *sharing_of_via_path,
|
||||
const std::vector<NodeID> &packed_shortest_path,
|
||||
const EdgeWeight min_edge_offset)
|
||||
{
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &existing_forward_heap = *engine_working_data.forward_heap_1;
|
||||
QueryHeap &existing_reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
QueryHeap &new_forward_heap = *engine_working_data.forward_heap_2;
|
||||
QueryHeap &new_reverse_heap = *engine_working_data.reverse_heap_2;
|
||||
|
||||
std::vector<NodeID> packed_s_v_path;
|
||||
std::vector<NodeID> packed_v_t_path;
|
||||
|
||||
std::vector<NodeID> partially_unpacked_shortest_path;
|
||||
std::vector<NodeID> partially_unpacked_via_path;
|
||||
|
||||
NodeID s_v_middle = SPECIAL_NODEID;
|
||||
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_reverse_heap.Insert(via_node, 0, via_node);
|
||||
// compute path <s,..,v> by reusing forward search from s
|
||||
while (!new_reverse_heap.Empty())
|
||||
{
|
||||
super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
|
||||
upper_bound_s_v_path_length, min_edge_offset, false);
|
||||
}
|
||||
// compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = SPECIAL_NODEID;
|
||||
int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_forward_heap.Insert(via_node, 0, via_node);
|
||||
while (!new_forward_heap.Empty())
|
||||
{
|
||||
super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
|
||||
upper_bound_of_v_t_path_length, min_edge_offset, true);
|
||||
}
|
||||
*real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||
|
||||
if (SPECIAL_NODEID == s_v_middle || SPECIAL_NODEID == v_t_middle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, s_v_middle,
|
||||
packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, v_t_middle,
|
||||
packed_v_t_path);
|
||||
|
||||
// partial unpacking, compute sharing
|
||||
// First partially unpack s-->v until paths deviate, note length of common path.
|
||||
const int64_t s_v_min_path_size =
|
||||
static_cast<int64_t>(std::min(packed_s_v_path.size(), packed_shortest_path.size())) - 1;
|
||||
for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size))
|
||||
{
|
||||
if (packed_s_v_path[current_node] == packed_shortest_path[current_node] &&
|
||||
packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1])
|
||||
{
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(
|
||||
packed_s_v_path[current_node], packed_s_v_path[current_node + 1]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packed_s_v_path[current_node] == packed_shortest_path[current_node])
|
||||
{
|
||||
super::UnpackEdge(packed_s_v_path[current_node],
|
||||
packed_s_v_path[current_node + 1],
|
||||
partially_unpacked_via_path);
|
||||
super::UnpackEdge(packed_shortest_path[current_node],
|
||||
packed_shortest_path[current_node + 1],
|
||||
partially_unpacked_shortest_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// traverse partially unpacked edge and note common prefix
|
||||
const int64_t packed_path_length =
|
||||
static_cast<int64_t>(std::min(partially_unpacked_via_path.size(),
|
||||
partially_unpacked_shortest_path.size())) -
|
||||
1;
|
||||
for (int64_t current_node = 0; (current_node < packed_path_length) &&
|
||||
(partially_unpacked_via_path[current_node] ==
|
||||
partially_unpacked_shortest_path[current_node] &&
|
||||
partially_unpacked_via_path[current_node + 1] ==
|
||||
partially_unpacked_shortest_path[current_node + 1]);
|
||||
++current_node)
|
||||
{
|
||||
EdgeID selected_edge =
|
||||
facade->FindEdgeInEitherDirection(partially_unpacked_via_path[current_node],
|
||||
partially_unpacked_via_path[current_node + 1]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(selected_edge).distance;
|
||||
}
|
||||
|
||||
// Second, partially unpack v-->t in reverse order until paths deviate and note lengths
|
||||
int64_t via_path_index = static_cast<int64_t>(packed_v_t_path.size()) - 1;
|
||||
int64_t shortest_path_index = static_cast<int64_t>(packed_shortest_path.size()) - 1;
|
||||
for (; via_path_index > 0 && shortest_path_index > 0;
|
||||
--via_path_index, --shortest_path_index)
|
||||
{
|
||||
if (packed_v_t_path[via_path_index - 1] ==
|
||||
packed_shortest_path[shortest_path_index - 1] &&
|
||||
packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
|
||||
{
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(
|
||||
packed_v_t_path[via_path_index - 1], packed_v_t_path[via_path_index]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
|
||||
{
|
||||
super::UnpackEdge(packed_v_t_path[via_path_index - 1],
|
||||
packed_v_t_path[via_path_index], partially_unpacked_via_path);
|
||||
super::UnpackEdge(packed_shortest_path[shortest_path_index - 1],
|
||||
packed_shortest_path[shortest_path_index],
|
||||
partially_unpacked_shortest_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
via_path_index = partially_unpacked_via_path.size() - 1;
|
||||
shortest_path_index = partially_unpacked_shortest_path.size() - 1;
|
||||
for (; via_path_index > 0 && shortest_path_index > 0;
|
||||
--via_path_index, --shortest_path_index)
|
||||
{
|
||||
if (partially_unpacked_via_path[via_path_index - 1] ==
|
||||
partially_unpacked_shortest_path[shortest_path_index - 1] &&
|
||||
partially_unpacked_via_path[via_path_index] ==
|
||||
partially_unpacked_shortest_path[shortest_path_index])
|
||||
{
|
||||
EdgeID edgeID = facade->FindEdgeInEitherDirection(
|
||||
partially_unpacked_via_path[via_path_index - 1],
|
||||
partially_unpacked_via_path[via_path_index]);
|
||||
*sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// finished partial unpacking spree! Amount of sharing is stored to appropriate pointer
|
||||
// variable
|
||||
}
|
||||
|
||||
// int approximateAmountOfSharing(
|
||||
// const NodeID alternate_path_middle_node_id,
|
||||
// QueryHeap & forward_heap,
|
||||
// QueryHeap & reverse_heap,
|
||||
// const std::vector<NodeID> & packed_shortest_path
|
||||
// ) const {
|
||||
// std::vector<NodeID> packed_alternate_path;
|
||||
// super::RetrievePackedPathFromHeap(
|
||||
// forward_heap,
|
||||
// reverse_heap,
|
||||
// alternate_path_middle_node_id,
|
||||
// packed_alternate_path
|
||||
// );
|
||||
|
||||
// if(packed_shortest_path.size() < 2 || packed_alternate_path.size() < 2) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int sharing = 0;
|
||||
// int aindex = 0;
|
||||
// //compute forward sharing
|
||||
// while( (packed_alternate_path[aindex] == packed_shortest_path[aindex]) &&
|
||||
// (packed_alternate_path[aindex+1] == packed_shortest_path[aindex+1]) ) {
|
||||
// // SimpleLogger().Write() << "retrieving edge (" <<
|
||||
// packed_alternate_path[aindex] << "," << packed_alternate_path[aindex+1] << ")";
|
||||
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
|
||||
// packed_alternate_path[aindex+1]);
|
||||
// sharing += facade->GetEdgeData(edgeID).distance;
|
||||
// ++aindex;
|
||||
// }
|
||||
|
||||
// aindex = packed_alternate_path.size()-1;
|
||||
// int bindex = packed_shortest_path.size()-1;
|
||||
// //compute backward sharing
|
||||
// while( aindex > 0 && bindex > 0 && (packed_alternate_path[aindex] ==
|
||||
// packed_shortest_path[bindex]) && (packed_alternate_path[aindex-1] ==
|
||||
// packed_shortest_path[bindex-1]) ) {
|
||||
// EdgeID edgeID = facade->FindEdgeInEitherDirection(packed_alternate_path[aindex],
|
||||
// packed_alternate_path[aindex-1]);
|
||||
// sharing += facade->GetEdgeData(edgeID).distance;
|
||||
// --aindex; --bindex;
|
||||
// }
|
||||
// return sharing;
|
||||
// }
|
||||
|
||||
// todo: reorder parameters
|
||||
template <bool is_forward_directed>
|
||||
void AlternativeRoutingStep(QueryHeap &heap1,
|
||||
QueryHeap &heap2,
|
||||
NodeID *middle_node,
|
||||
int *upper_bound_to_shortest_path_distance,
|
||||
std::vector<NodeID> &search_space_intersection,
|
||||
std::vector<SearchSpaceEdge> &search_space,
|
||||
const EdgeWeight min_edge_offset) const
|
||||
{
|
||||
QueryHeap &forward_heap = (is_forward_directed ? heap1 : heap2);
|
||||
QueryHeap &reverse_heap = (is_forward_directed ? heap2 : heap1);
|
||||
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
// const NodeID parentnode = forward_heap.GetData(node).parent;
|
||||
// SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge ("
|
||||
// << parentnode << "," << node << "), dist: " << distance;
|
||||
|
||||
const int scaled_distance =
|
||||
static_cast<int>((distance + min_edge_offset) / (1. + VIAPATH_EPSILON));
|
||||
if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
|
||||
(scaled_distance > *upper_bound_to_shortest_path_distance))
|
||||
{
|
||||
forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
search_space.emplace_back(forward_heap.GetData(node).parent, node);
|
||||
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
search_space_intersection.emplace_back(node);
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if (new_distance < *upper_bound_to_shortest_path_distance)
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
{
|
||||
*middle_node = node;
|
||||
*upper_bound_to_shortest_path_distance = new_distance;
|
||||
// SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at
|
||||
// distance " << new_distance;
|
||||
// } else {
|
||||
// SimpleLogger().Write() << "discarded middle_node " << *middle_node << "
|
||||
// at distance " << new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
const bool edge_is_forward_directed =
|
||||
(is_forward_directed ? data.forward : data.backward);
|
||||
if (edge_is_forward_directed)
|
||||
{
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT(edge_weight > 0);
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!forward_heap.WasInserted(to))
|
||||
{
|
||||
forward_heap.Insert(to, to_distance, node);
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < forward_heap.GetKey(to))
|
||||
{
|
||||
// new parent
|
||||
forward_heap.GetData(to).parent = node;
|
||||
// decreased distance
|
||||
forward_heap.DecreaseKey(to, to_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// conduct T-Test
|
||||
bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap,
|
||||
QueryHeap &existing_reverse_heap,
|
||||
QueryHeap &new_forward_heap,
|
||||
QueryHeap &new_reverse_heap,
|
||||
const RankedCandidateNode &candidate,
|
||||
const int length_of_shortest_path,
|
||||
int *length_of_via_path,
|
||||
NodeID *s_v_middle,
|
||||
NodeID *v_t_middle,
|
||||
const EdgeWeight min_edge_offset) const
|
||||
{
|
||||
new_forward_heap.Clear();
|
||||
new_reverse_heap.Clear();
|
||||
std::vector<NodeID> packed_s_v_path;
|
||||
std::vector<NodeID> packed_v_t_path;
|
||||
|
||||
*s_v_middle = SPECIAL_NODEID;
|
||||
int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
|
||||
// compute path <s,..,v> by reusing forward search from s
|
||||
new_reverse_heap.Insert(candidate.node, 0, candidate.node);
|
||||
while (new_reverse_heap.Size() > 0)
|
||||
{
|
||||
super::RoutingStep(new_reverse_heap, existing_forward_heap, *s_v_middle,
|
||||
upper_bound_s_v_path_length, min_edge_offset, false);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute path <v,..,t> by reusing backward search from t
|
||||
*v_t_middle = SPECIAL_NODEID;
|
||||
int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
|
||||
new_forward_heap.Insert(candidate.node, 0, candidate.node);
|
||||
while (new_forward_heap.Size() > 0)
|
||||
{
|
||||
super::RoutingStep(new_forward_heap, existing_reverse_heap, *v_t_middle,
|
||||
upper_bound_of_v_t_path_length, min_edge_offset, true);
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;
|
||||
|
||||
// retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, *s_v_middle,
|
||||
packed_s_v_path);
|
||||
|
||||
super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, *v_t_middle,
|
||||
packed_v_t_path);
|
||||
|
||||
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
||||
if (SPECIAL_NODEID == s_P)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SPECIAL_NODEID == t_P)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path);
|
||||
int unpacked_until_distance = 0;
|
||||
|
||||
std::stack<SearchSpaceEdge> unpack_stack;
|
||||
// Traverse path s-->v
|
||||
for (std::size_t i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i)
|
||||
{
|
||||
const EdgeID current_edge_id =
|
||||
facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
const int length_of_current_edge = facade->GetEdgeData(current_edge_id).distance;
|
||||
if ((length_of_current_edge + unpacked_until_distance) >= T_threshold)
|
||||
{
|
||||
unpack_stack.emplace(packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpacked_until_distance += length_of_current_edge;
|
||||
s_P = packed_s_v_path[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpack_stack.empty())
|
||||
{
|
||||
const SearchSpaceEdge via_path_edge = unpack_stack.top();
|
||||
unpack_stack.pop();
|
||||
EdgeID edge_in_via_path_id =
|
||||
facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);
|
||||
|
||||
if (SPECIAL_EDGEID == edge_in_via_path_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id);
|
||||
const bool current_edge_is_shortcut = current_edge_data.shortcut;
|
||||
if (current_edge_is_shortcut)
|
||||
{
|
||||
const NodeID via_path_middle_node_id = current_edge_data.id;
|
||||
const EdgeID second_segment_edge_id = facade->FindEdgeInEitherDirection(
|
||||
via_path_middle_node_id, via_path_edge.second);
|
||||
const int second_segment_length =
|
||||
facade->GetEdgeData(second_segment_edge_id).distance;
|
||||
// attention: !unpacking in reverse!
|
||||
// Check if second segment is the one to go over treshold? if yes add second segment
|
||||
// to stack, else push first segment to stack and add distance of second one.
|
||||
if (unpacked_until_distance + second_segment_length >= T_threshold)
|
||||
{
|
||||
unpack_stack.emplace(via_path_middle_node_id, via_path_edge.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpacked_until_distance += second_segment_length;
|
||||
unpack_stack.emplace(via_path_edge.first, via_path_middle_node_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpacked_until_distance += current_edge_data.distance;
|
||||
s_P = via_path_edge.first;
|
||||
}
|
||||
}
|
||||
|
||||
int t_test_path_length = unpacked_until_distance;
|
||||
unpacked_until_distance = 0;
|
||||
// Traverse path s-->v
|
||||
BOOST_ASSERT(!packed_v_t_path.empty());
|
||||
for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1);
|
||||
(i < packed_path_length) && unpack_stack.empty(); ++i)
|
||||
{
|
||||
const EdgeID edgeID =
|
||||
facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
int length_of_current_edge = facade->GetEdgeData(edgeID).distance;
|
||||
if (length_of_current_edge + unpacked_until_distance >= T_threshold)
|
||||
{
|
||||
unpack_stack.emplace(packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpacked_until_distance += length_of_current_edge;
|
||||
t_P = packed_v_t_path[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpack_stack.empty())
|
||||
{
|
||||
const SearchSpaceEdge via_path_edge = unpack_stack.top();
|
||||
unpack_stack.pop();
|
||||
EdgeID edge_in_via_path_id =
|
||||
facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);
|
||||
if (SPECIAL_EDGEID == edge_in_via_path_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const EdgeData ¤t_edge_data = facade->GetEdgeData(edge_in_via_path_id);
|
||||
const bool IsViaEdgeShortCut = current_edge_data.shortcut;
|
||||
if (IsViaEdgeShortCut)
|
||||
{
|
||||
const NodeID middleOfViaPath = current_edge_data.id;
|
||||
EdgeID edgeIDOfFirstSegment =
|
||||
facade->FindEdgeInEitherDirection(via_path_edge.first, middleOfViaPath);
|
||||
int lengthOfFirstSegment = facade->GetEdgeData(edgeIDOfFirstSegment).distance;
|
||||
// Check if first segment is the one to go over treshold? if yes first segment to
|
||||
// stack, else push second segment to stack and add distance of first one.
|
||||
if (unpacked_until_distance + lengthOfFirstSegment >= T_threshold)
|
||||
{
|
||||
unpack_stack.emplace(via_path_edge.first, middleOfViaPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
unpacked_until_distance += lengthOfFirstSegment;
|
||||
unpack_stack.emplace(middleOfViaPath, via_path_edge.second);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpacked_until_distance += current_edge_data.distance;
|
||||
t_P = via_path_edge.second;
|
||||
}
|
||||
}
|
||||
|
||||
t_test_path_length += unpacked_until_distance;
|
||||
// Run actual T-Test query and compare if distances equal.
|
||||
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &forward_heap3 = *engine_working_data.forward_heap_3;
|
||||
QueryHeap &reverse_heap3 = *engine_working_data.reverse_heap_3;
|
||||
int upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
forward_heap3.Insert(s_P, 0, s_P);
|
||||
reverse_heap3.Insert(t_P, 0, t_P);
|
||||
// exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path
|
||||
while ((forward_heap3.Size() + reverse_heap3.Size()) > 0)
|
||||
{
|
||||
if (!forward_heap3.Empty())
|
||||
{
|
||||
super::RoutingStep(forward_heap3, reverse_heap3, middle, upper_bound,
|
||||
min_edge_offset, true);
|
||||
}
|
||||
if (!reverse_heap3.Empty())
|
||||
{
|
||||
super::RoutingStep(reverse_heap3, forward_heap3, middle, upper_bound,
|
||||
min_edge_offset, false);
|
||||
}
|
||||
}
|
||||
return (upper_bound <= t_test_path_length);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ALTERNATIVE_PATH_ROUTING_HPP */
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DIRECT_SHORTEST_PATH_HPP
|
||||
#define DIRECT_SHORTEST_PATH_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <iterator>
|
||||
|
||||
#include "routing_base.hpp"
|
||||
#include "../data_structures/search_engine_data.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
/// This is a striped down version of the general shortest path algorithm.
|
||||
/// The general algorithm always computes two queries for each leg. This is only
|
||||
/// necessary in case of vias, where the directions of the start node is constrainted
|
||||
/// by the previous route.
|
||||
/// This variation is only an optimazation for graphs with slow queries, for example
|
||||
/// not fully contracted graphs.
|
||||
template <class DataFacadeT>
|
||||
class DirectShortestPathRouting final
|
||||
: public BasicRoutingInterface<DataFacadeT, DirectShortestPathRouting<DataFacadeT>>
|
||||
{
|
||||
using super = BasicRoutingInterface<DataFacadeT, DirectShortestPathRouting<DataFacadeT>>;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
public:
|
||||
DirectShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
~DirectShortestPathRouting() {}
|
||||
|
||||
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<bool> &uturn_indicators,
|
||||
InternalRouteResult &raw_route_data) const
|
||||
{
|
||||
(void)uturn_indicators; // unused
|
||||
|
||||
// Get distance to next pair of target nodes.
|
||||
BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
|
||||
"Direct Shortest Path Query only accepts a single source and target pair. Multiple ones have been specified.");
|
||||
const auto& phantom_node_pair = phantom_nodes_vector.front();
|
||||
const auto& source_phantom = phantom_node_pair.source_phantom;
|
||||
const auto& target_phantom = phantom_node_pair.target_phantom;
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
|
||||
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
BOOST_ASSERT(source_phantom.is_valid());
|
||||
BOOST_ASSERT(target_phantom.is_valid());
|
||||
|
||||
if (source_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_node_id,
|
||||
-source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_node_id);
|
||||
}
|
||||
if (source_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_node_id,
|
||||
-source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
if (target_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.forward_node_id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_node_id);
|
||||
}
|
||||
|
||||
if (target_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.reverse_node_id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
int distance = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_leg;
|
||||
|
||||
if (super::facade->GetCoreSize() > 0)
|
||||
{
|
||||
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2);
|
||||
QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2);
|
||||
forward_core_heap.Clear();
|
||||
reverse_core_heap.Clear();
|
||||
|
||||
|
||||
super::SearchWithCore(forward_heap, reverse_heap, forward_core_heap, reverse_core_heap,
|
||||
distance, packed_leg);
|
||||
}
|
||||
else
|
||||
{
|
||||
super::Search(forward_heap, reverse_heap, distance, packed_leg);
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (INVALID_EDGE_WEIGHT == distance)
|
||||
{
|
||||
raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
|
||||
raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(!packed_leg.empty(), "packed path empty");
|
||||
|
||||
raw_route_data.shortest_path_length = distance;
|
||||
raw_route_data.unpacked_path_segments.resize(1);
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(packed_leg.front() != phantom_node_pair.source_phantom.forward_node_id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(packed_leg.back() != phantom_node_pair.target_phantom.forward_node_id));
|
||||
|
||||
super::UnpackPath(packed_leg.begin(), packed_leg.end(), phantom_node_pair, raw_route_data.unpacked_path_segments.front());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DIRECT_SHORTEST_PATH_HPP */
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MANY_TO_MANY_ROUTING_HPP
|
||||
#define MANY_TO_MANY_ROUTING_HPP
|
||||
|
||||
#include "routing_base.hpp"
|
||||
#include "../data_structures/search_engine_data.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
template <class DataFacadeT>
|
||||
class ManyToManyRouting final
|
||||
: public BasicRoutingInterface<DataFacadeT, ManyToManyRouting<DataFacadeT>>
|
||||
{
|
||||
using super = BasicRoutingInterface<DataFacadeT, ManyToManyRouting<DataFacadeT>>;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
struct NodeBucket
|
||||
{
|
||||
unsigned target_id; // essentially a row in the distance matrix
|
||||
EdgeWeight distance;
|
||||
NodeBucket(const unsigned target_id, const EdgeWeight distance)
|
||||
: target_id(target_id), distance(distance)
|
||||
{
|
||||
}
|
||||
};
|
||||
using SearchSpaceWithBuckets = std::unordered_map<NodeID, std::vector<NodeBucket>>;
|
||||
|
||||
public:
|
||||
ManyToManyRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
~ManyToManyRouting() {}
|
||||
|
||||
std::shared_ptr<std::vector<EdgeWeight>>
|
||||
operator()(const std::vector<PhantomNode> &phantom_sources_array, const std::vector<PhantomNode> &phantom_targets_array) const
|
||||
{
|
||||
const auto number_of_sources = phantom_sources_array.size();
|
||||
const auto number_of_targets = phantom_targets_array.size();
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table =
|
||||
std::make_shared<std::vector<EdgeWeight>>(number_of_targets * number_of_sources,
|
||||
std::numeric_limits<EdgeWeight>::max());
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &query_heap = *(engine_working_data.forward_heap_1);
|
||||
|
||||
SearchSpaceWithBuckets search_space_with_buckets;
|
||||
|
||||
unsigned target_id = 0;
|
||||
for (const auto &phantom : phantom_targets_array)
|
||||
{
|
||||
query_heap.Clear();
|
||||
// insert target(s) at distance 0
|
||||
|
||||
if (SPECIAL_NODEID != phantom.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom.forward_node_id,
|
||||
phantom.GetForwardWeightPlusOffset(),
|
||||
phantom.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != phantom.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom.reverse_node_id,
|
||||
phantom.GetReverseWeightPlusOffset(),
|
||||
phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
BackwardRoutingStep(target_id, query_heap, search_space_with_buckets);
|
||||
}
|
||||
++target_id;
|
||||
}
|
||||
|
||||
// for each source do forward search
|
||||
unsigned source_id = 0;
|
||||
for (const auto &phantom : phantom_sources_array)
|
||||
{
|
||||
query_heap.Clear();
|
||||
// insert target(s) at distance 0
|
||||
|
||||
if (SPECIAL_NODEID != phantom.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom.forward_node_id,
|
||||
-phantom.GetForwardWeightPlusOffset(),
|
||||
phantom.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != phantom.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(phantom.reverse_node_id,
|
||||
-phantom.GetReverseWeightPlusOffset(),
|
||||
phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
ForwardRoutingStep(source_id, number_of_targets, query_heap,
|
||||
search_space_with_buckets, result_table);
|
||||
}
|
||||
|
||||
++source_id;
|
||||
}
|
||||
// BOOST_ASSERT(source_id == target_id);
|
||||
return result_table;
|
||||
}
|
||||
|
||||
void ForwardRoutingStep(const unsigned source_id,
|
||||
const unsigned number_of_targets,
|
||||
QueryHeap &query_heap,
|
||||
const SearchSpaceWithBuckets &search_space_with_buckets,
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table) const
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const int source_distance = query_heap.GetKey(node);
|
||||
|
||||
// check if each encountered node has an entry
|
||||
const auto bucket_iterator = search_space_with_buckets.find(node);
|
||||
// iterate bucket if there exists one
|
||||
if (bucket_iterator != search_space_with_buckets.end())
|
||||
{
|
||||
const std::vector<NodeBucket> &bucket_list = bucket_iterator->second;
|
||||
for (const NodeBucket ¤t_bucket : bucket_list)
|
||||
{
|
||||
// get target id from bucket entry
|
||||
const unsigned target_id = current_bucket.target_id;
|
||||
const int target_distance = current_bucket.distance;
|
||||
const EdgeWeight current_distance =
|
||||
(*result_table)[source_id * number_of_targets + target_id];
|
||||
// check if new distance is better
|
||||
const EdgeWeight new_distance = source_distance + target_distance;
|
||||
if (new_distance >= 0 && new_distance < current_distance)
|
||||
{
|
||||
(*result_table)[source_id * number_of_targets + target_id] =
|
||||
(source_distance + target_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StallAtNode<true>(node, source_distance, query_heap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
RelaxOutgoingEdges<true>(node, source_distance, query_heap);
|
||||
}
|
||||
|
||||
void BackwardRoutingStep(const unsigned target_id,
|
||||
QueryHeap &query_heap,
|
||||
SearchSpaceWithBuckets &search_space_with_buckets) const
|
||||
{
|
||||
const NodeID node = query_heap.DeleteMin();
|
||||
const int target_distance = query_heap.GetKey(node);
|
||||
|
||||
// store settled nodes in search space bucket
|
||||
search_space_with_buckets[node].emplace_back(target_id, target_distance);
|
||||
|
||||
if (StallAtNode<false>(node, target_distance, query_heap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RelaxOutgoingEdges<false>(node, target_distance, query_heap);
|
||||
}
|
||||
|
||||
template <bool forward_direction>
|
||||
inline void
|
||||
RelaxOutgoingEdges(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
|
||||
{
|
||||
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
const bool direction_flag = (forward_direction ? data.forward : data.backward);
|
||||
if (direction_flag)
|
||||
{
|
||||
const NodeID to = super::facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!query_heap.WasInserted(to))
|
||||
{
|
||||
query_heap.Insert(to, to_distance, node);
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < query_heap.GetKey(to))
|
||||
{
|
||||
// new parent
|
||||
query_heap.GetData(to).parent = node;
|
||||
query_heap.DecreaseKey(to, to_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stalling
|
||||
template <bool forward_direction>
|
||||
inline bool
|
||||
StallAtNode(const NodeID node, const EdgeWeight distance, QueryHeap &query_heap) const
|
||||
{
|
||||
for (auto edge : super::facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &data = super::facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = super::facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
if (query_heap.WasInserted(to))
|
||||
{
|
||||
if (query_heap.GetKey(to) + edge_weight < distance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MAP_MATCHING_HPP
|
||||
#define MAP_MATCHING_HPP
|
||||
|
||||
#include "routing_base.hpp"
|
||||
|
||||
#include "../algorithms/coordinate_calculation.hpp"
|
||||
#include "../data_structures/hidden_markov_model.hpp"
|
||||
#include "../util/json_logger.hpp"
|
||||
#include "../util/matching_debug_info.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace matching
|
||||
{
|
||||
|
||||
struct SubMatching
|
||||
{
|
||||
std::vector<PhantomNode> nodes;
|
||||
std::vector<unsigned> indices;
|
||||
double length;
|
||||
double confidence;
|
||||
};
|
||||
|
||||
using CandidateList = std::vector<PhantomNodeWithDistance>;
|
||||
using CandidateLists = std::vector<CandidateList>;
|
||||
using HMM = HiddenMarkovModel<CandidateLists>;
|
||||
using SubMatchingList = std::vector<SubMatching>;
|
||||
|
||||
constexpr static const unsigned MAX_BROKEN_STATES = 10;
|
||||
|
||||
constexpr static const double MAX_SPEED = 180 / 3.6; // 180km -> m/s
|
||||
constexpr static const unsigned SUSPICIOUS_DISTANCE_DELTA = 100;
|
||||
}
|
||||
}
|
||||
|
||||
// implements a hidden markov model map matching algorithm
|
||||
template <class DataFacadeT>
|
||||
class MapMatching final : public BasicRoutingInterface<DataFacadeT, MapMatching<DataFacadeT>>
|
||||
{
|
||||
using super = BasicRoutingInterface<DataFacadeT, MapMatching<DataFacadeT>>;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
unsigned GetMedianSampleTime(const std::vector<unsigned>& timestamps) const
|
||||
{
|
||||
BOOST_ASSERT(timestamps.size() > 1);
|
||||
|
||||
std::vector<unsigned> sample_times(timestamps.size());
|
||||
|
||||
std::adjacent_difference(timestamps.begin(), timestamps.end(), sample_times.begin());
|
||||
|
||||
// don't use first element of sample_times -> will not be a difference.
|
||||
auto first_elem = std::next(sample_times.begin());
|
||||
auto median = first_elem + std::distance(first_elem, sample_times.end())/2;
|
||||
std::nth_element(first_elem, median, sample_times.end());
|
||||
return *median;
|
||||
}
|
||||
|
||||
public:
|
||||
MapMatching(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(const osrm::matching::CandidateLists &candidates_list,
|
||||
const std::vector<FixedPointCoordinate> &trace_coordinates,
|
||||
const std::vector<unsigned> &trace_timestamps,
|
||||
const double matching_beta,
|
||||
const double gps_precision,
|
||||
osrm::matching::SubMatchingList &sub_matchings) const
|
||||
{
|
||||
BOOST_ASSERT(candidates_list.size() == trace_coordinates.size());
|
||||
BOOST_ASSERT(candidates_list.size() > 1);
|
||||
|
||||
const bool use_timestamps = trace_timestamps.size() > 1;
|
||||
|
||||
const auto median_sample_time = [&]() {
|
||||
if (use_timestamps)
|
||||
{
|
||||
return std::max(1u, GetMedianSampleTime(trace_timestamps));
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1u;
|
||||
}
|
||||
}();
|
||||
const auto max_broken_time = median_sample_time * osrm::matching::MAX_BROKEN_STATES;
|
||||
const auto max_distance_delta = [&]() {
|
||||
if (use_timestamps)
|
||||
{
|
||||
return median_sample_time * osrm::matching::MAX_SPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
}();
|
||||
|
||||
// TODO replace default values with table lookup based on sampling frequency
|
||||
EmissionLogProbability emission_log_probability(gps_precision);
|
||||
TransitionLogProbability transition_log_probability(matching_beta);
|
||||
|
||||
osrm::matching::HMM model(candidates_list, emission_log_probability);
|
||||
|
||||
std::size_t initial_timestamp = model.initialize(0);
|
||||
if (initial_timestamp == osrm::matching::INVALID_STATE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MatchingDebugInfo matching_debug(osrm::json::Logger::get());
|
||||
matching_debug.initialize(candidates_list);
|
||||
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
|
||||
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
|
||||
|
||||
std::size_t breakage_begin = osrm::matching::INVALID_STATE;
|
||||
std::vector<std::size_t> split_points;
|
||||
std::vector<std::size_t> prev_unbroken_timestamps;
|
||||
prev_unbroken_timestamps.reserve(candidates_list.size());
|
||||
prev_unbroken_timestamps.push_back(initial_timestamp);
|
||||
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
||||
{
|
||||
// breakage recover has removed all previous good points
|
||||
bool trace_split = prev_unbroken_timestamps.empty();
|
||||
|
||||
// use temporal information if available to determine a split
|
||||
if (use_timestamps)
|
||||
{
|
||||
trace_split =
|
||||
trace_split ||
|
||||
(trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
|
||||
max_broken_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_split = trace_split || (t - prev_unbroken_timestamps.back() >
|
||||
osrm::matching::MAX_BROKEN_STATES);
|
||||
}
|
||||
|
||||
if (trace_split)
|
||||
{
|
||||
std::size_t split_index = t;
|
||||
if (breakage_begin != osrm::matching::INVALID_STATE)
|
||||
{
|
||||
split_index = breakage_begin;
|
||||
breakage_begin = osrm::matching::INVALID_STATE;
|
||||
}
|
||||
split_points.push_back(split_index);
|
||||
|
||||
// note: this preserves everything before split_index
|
||||
model.clear(split_index);
|
||||
std::size_t new_start = model.initialize(split_index);
|
||||
// no new start was found -> stop viterbi calculation
|
||||
if (new_start == osrm::matching::INVALID_STATE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
prev_unbroken_timestamps.clear();
|
||||
prev_unbroken_timestamps.push_back(new_start);
|
||||
// Important: We potentially go back here!
|
||||
// However since t > new_start >= breakge_begin
|
||||
// we can only reset trace_coordindates.size() times.
|
||||
t = new_start + 1;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!prev_unbroken_timestamps.empty());
|
||||
const std::size_t prev_unbroken_timestamp = prev_unbroken_timestamps.back();
|
||||
|
||||
const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
|
||||
const auto &prev_pruned = model.pruned[prev_unbroken_timestamp];
|
||||
const auto &prev_unbroken_timestamps_list = candidates_list[prev_unbroken_timestamp];
|
||||
const auto &prev_coordinate = trace_coordinates[prev_unbroken_timestamp];
|
||||
|
||||
auto ¤t_viterbi = model.viterbi[t];
|
||||
auto ¤t_pruned = model.pruned[t];
|
||||
auto ¤t_suspicious = model.suspicious[t];
|
||||
auto ¤t_parents = model.parents[t];
|
||||
auto ¤t_lengths = model.path_lengths[t];
|
||||
const auto ¤t_timestamps_list = candidates_list[t];
|
||||
const auto ¤t_coordinate = trace_coordinates[t];
|
||||
|
||||
const auto haversine_distance = coordinate_calculation::haversine_distance(prev_coordinate, current_coordinate);
|
||||
|
||||
// compute d_t for this timestamp and the next one
|
||||
for (const auto s : osrm::irange<std::size_t>(0u, prev_viterbi.size()))
|
||||
{
|
||||
if (prev_pruned[s])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto s_prime : osrm::irange<std::size_t>(0u, current_viterbi.size()))
|
||||
{
|
||||
// how likely is candidate s_prime at time t to be emitted?
|
||||
// FIXME this can be pre-computed
|
||||
const double emission_pr =
|
||||
emission_log_probability(candidates_list[t][s_prime].distance);
|
||||
double new_value = prev_viterbi[s] + emission_pr;
|
||||
if (current_viterbi[s_prime] > new_value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
// get distance diff between loc1/2 and locs/s_prime
|
||||
const auto network_distance = super::get_network_distance(
|
||||
forward_heap, reverse_heap, prev_unbroken_timestamps_list[s].phantom_node,
|
||||
current_timestamps_list[s_prime].phantom_node);
|
||||
|
||||
const auto d_t = std::abs(network_distance - haversine_distance);
|
||||
|
||||
// very low probability transition -> prune
|
||||
if (d_t >= max_distance_delta)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const double transition_pr = transition_log_probability(d_t);
|
||||
new_value += transition_pr;
|
||||
|
||||
matching_debug.add_transition_info(prev_unbroken_timestamp, t, s, s_prime,
|
||||
prev_viterbi[s], emission_pr, transition_pr,
|
||||
network_distance, haversine_distance);
|
||||
|
||||
if (new_value > current_viterbi[s_prime])
|
||||
{
|
||||
current_viterbi[s_prime] = new_value;
|
||||
current_parents[s_prime] = std::make_pair(prev_unbroken_timestamp, s);
|
||||
current_lengths[s_prime] = network_distance;
|
||||
current_pruned[s_prime] = false;
|
||||
current_suspicious[s_prime] = d_t > osrm::matching::SUSPICIOUS_DISTANCE_DELTA;
|
||||
model.breakage[t] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (model.breakage[t])
|
||||
{
|
||||
// save start of breakage -> we need this as split point
|
||||
if (t < breakage_begin)
|
||||
{
|
||||
breakage_begin = t;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
|
||||
// remove both ends of the breakage
|
||||
prev_unbroken_timestamps.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_unbroken_timestamps.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
matching_debug.set_viterbi(model.viterbi, model.pruned, model.suspicious);
|
||||
|
||||
if (!prev_unbroken_timestamps.empty())
|
||||
{
|
||||
split_points.push_back(prev_unbroken_timestamps.back() + 1);
|
||||
}
|
||||
|
||||
std::size_t sub_matching_begin = initial_timestamp;
|
||||
for (const auto sub_matching_end : split_points)
|
||||
{
|
||||
osrm::matching::SubMatching matching;
|
||||
|
||||
std::size_t parent_timestamp_index = sub_matching_end - 1;
|
||||
while (parent_timestamp_index >= sub_matching_begin &&
|
||||
model.breakage[parent_timestamp_index])
|
||||
{
|
||||
--parent_timestamp_index;
|
||||
}
|
||||
while (sub_matching_begin < sub_matching_end &&
|
||||
model.breakage[sub_matching_begin])
|
||||
{
|
||||
++sub_matching_begin;
|
||||
}
|
||||
|
||||
// matchings that only consist of one candidate are invalid
|
||||
if (parent_timestamp_index - sub_matching_begin + 1 < 2)
|
||||
{
|
||||
sub_matching_begin = sub_matching_end;
|
||||
continue;
|
||||
}
|
||||
|
||||
// loop through the columns, and only compare the last entry
|
||||
const auto max_element_iter =
|
||||
std::max_element(model.viterbi[parent_timestamp_index].begin(),
|
||||
model.viterbi[parent_timestamp_index].end());
|
||||
|
||||
std::size_t parent_candidate_index =
|
||||
std::distance(model.viterbi[parent_timestamp_index].begin(), max_element_iter);
|
||||
|
||||
std::deque<std::pair<std::size_t, std::size_t>> reconstructed_indices;
|
||||
while (parent_timestamp_index > sub_matching_begin)
|
||||
{
|
||||
if (model.breakage[parent_timestamp_index])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
reconstructed_indices.emplace_front(parent_timestamp_index, parent_candidate_index);
|
||||
const auto &next = model.parents[parent_timestamp_index][parent_candidate_index];
|
||||
// make sure we can never get stuck in this loop
|
||||
if (parent_timestamp_index == next.first)
|
||||
{
|
||||
break;
|
||||
}
|
||||
parent_timestamp_index = next.first;
|
||||
parent_candidate_index = next.second;
|
||||
}
|
||||
reconstructed_indices.emplace_front(parent_timestamp_index, parent_candidate_index);
|
||||
if (reconstructed_indices.size() < 2)
|
||||
{
|
||||
sub_matching_begin = sub_matching_end;
|
||||
continue;
|
||||
}
|
||||
|
||||
matching.length = 0.0f;
|
||||
matching.nodes.resize(reconstructed_indices.size());
|
||||
matching.indices.resize(reconstructed_indices.size());
|
||||
for (const auto i : osrm::irange<std::size_t>(0u, reconstructed_indices.size()))
|
||||
{
|
||||
const auto timestamp_index = reconstructed_indices[i].first;
|
||||
const auto location_index = reconstructed_indices[i].second;
|
||||
|
||||
matching.indices[i] = timestamp_index;
|
||||
matching.nodes[i] = candidates_list[timestamp_index][location_index].phantom_node;
|
||||
matching.length += model.path_lengths[timestamp_index][location_index];
|
||||
|
||||
matching_debug.add_chosen(timestamp_index, location_index);
|
||||
}
|
||||
|
||||
sub_matchings.push_back(matching);
|
||||
sub_matching_begin = sub_matching_end;
|
||||
}
|
||||
matching_debug.add_breakage(model.breakage);
|
||||
}
|
||||
};
|
||||
|
||||
//[1] "Hidden Markov Map Matching Through Noise and Sparseness"; P. Newson and J. Krumm; 2009; ACM
|
||||
// GIS
|
||||
|
||||
#endif /* MAP_MATCHING_HPP */
|
||||
@@ -0,0 +1,687 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ROUTING_BASE_HPP
|
||||
#define ROUTING_BASE_HPP
|
||||
|
||||
#include "../algorithms/coordinate_calculation.hpp"
|
||||
#include "../data_structures/internal_route_result.hpp"
|
||||
#include "../data_structures/search_engine_data.hpp"
|
||||
#include "../data_structures/turn_instructions.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <stack>
|
||||
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_1;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_1;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_2;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::forward_heap_3;
|
||||
SearchEngineData::SearchEngineHeapPtr SearchEngineData::reverse_heap_3;
|
||||
|
||||
template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
||||
{
|
||||
private:
|
||||
using EdgeData = typename DataFacadeT::EdgeData;
|
||||
|
||||
protected:
|
||||
DataFacadeT *facade;
|
||||
|
||||
public:
|
||||
BasicRoutingInterface() = delete;
|
||||
BasicRoutingInterface(const BasicRoutingInterface &) = delete;
|
||||
explicit BasicRoutingInterface(DataFacadeT *facade) : facade(facade) {}
|
||||
~BasicRoutingInterface() {}
|
||||
|
||||
// min_edge_offset is needed in case we use multiple
|
||||
// nodes as start/target nodes with different (even negative) offsets.
|
||||
// In that case the termination criterion is not correct
|
||||
// anymore.
|
||||
//
|
||||
// Example:
|
||||
// forward heap: a(-100), b(0),
|
||||
// reverse heap: c(0), d(100)
|
||||
//
|
||||
// a --- d
|
||||
// \ /
|
||||
// / \
|
||||
// b --- c
|
||||
//
|
||||
// This is equivalent to running a bi-directional Dijkstra on the following graph:
|
||||
//
|
||||
// a --- d
|
||||
// / \ / \
|
||||
// y x z
|
||||
// \ / \ /
|
||||
// b --- c
|
||||
//
|
||||
// The graph is constructed by inserting nodes y and z that are connected to the initial nodes
|
||||
// using edges (y, a) with weight -100, (y, b) with weight 0 and,
|
||||
// (d, z) with weight 100, (c, z) with weight 0 corresponding.
|
||||
// Since we are dealing with a graph that contains _negative_ edges,
|
||||
// we need to add an offset to the termination criterion.
|
||||
void RoutingStep(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node_id,
|
||||
int &upper_bound,
|
||||
int min_edge_offset,
|
||||
const bool forward_direction,
|
||||
const bool stalling = true) const
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int distance = forward_heap.GetKey(node);
|
||||
|
||||
if (reverse_heap.WasInserted(node))
|
||||
{
|
||||
const int new_distance = reverse_heap.GetKey(node) + distance;
|
||||
if (new_distance < upper_bound)
|
||||
{
|
||||
if (new_distance >= 0)
|
||||
{
|
||||
middle_node_id = node;
|
||||
upper_bound = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we don't terminate too early if we initialize the distance
|
||||
// for the nodes in the forward heap with the forward/reverse offset
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
if (distance + min_edge_offset > upper_bound)
|
||||
{
|
||||
forward_heap.DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// Stalling
|
||||
if (stalling)
|
||||
{
|
||||
for (const auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
||||
if (reverse_flag)
|
||||
{
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
|
||||
if (forward_heap.WasInserted(to))
|
||||
{
|
||||
if (forward_heap.GetKey(to) + edge_weight < distance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto edge : facade->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const EdgeData &data = facade->GetEdgeData(edge);
|
||||
bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
|
||||
if (forward_directionFlag)
|
||||
{
|
||||
|
||||
const NodeID to = facade->GetTarget(edge);
|
||||
const int edge_weight = data.distance;
|
||||
|
||||
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
||||
const int to_distance = distance + edge_weight;
|
||||
|
||||
// New Node discovered -> Add to Heap + Node Info Storage
|
||||
if (!forward_heap.WasInserted(to))
|
||||
{
|
||||
forward_heap.Insert(to, to_distance, node);
|
||||
}
|
||||
// Found a shorter Path -> Update distance
|
||||
else if (to_distance < forward_heap.GetKey(to))
|
||||
{
|
||||
// new parent
|
||||
forward_heap.GetData(to).parent = node;
|
||||
forward_heap.DecreaseKey(to, to_distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RandomIter>
|
||||
void UnpackPath(RandomIter packed_path_begin,
|
||||
RandomIter packed_path_end,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
std::vector<PathData> &unpacked_path) const
|
||||
{
|
||||
const bool start_traversed_in_reverse =
|
||||
(*packed_path_begin != phantom_node_pair.source_phantom.forward_node_id);
|
||||
const bool target_traversed_in_reverse =
|
||||
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_node_id);
|
||||
|
||||
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||
|
||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for (auto current = std::prev(packed_path_end); current != packed_path_begin;
|
||||
current = std::prev(current))
|
||||
{
|
||||
recursion_stack.emplace(*std::prev(current), *current);
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
// edge.first edge.second
|
||||
// *------------------>*
|
||||
// edge_id
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
// facade->FindEdge does not suffice here in case of shortcuts.
|
||||
// The above explanation unclear? Think!
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
// edge.first edge.second
|
||||
// *<------------------*
|
||||
// edge_id
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != INVALID_EDGE_WEIGHT, "edge id invalid");
|
||||
|
||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if (ed.shortcut)
|
||||
{ // unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
// again, we need to this in reversed order
|
||||
recursion_stack.emplace(middle_node_id, edge.second);
|
||||
recursion_stack.emplace(edge.first, middle_node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "original edge flagged as shortcut");
|
||||
unsigned name_index = facade->GetNameIndexFromEdgeID(ed.id);
|
||||
const TurnInstruction turn_instruction = facade->GetTurnInstructionForEdgeID(ed.id);
|
||||
const TravelMode travel_mode = facade->GetTravelModeForEdgeID(ed.id);
|
||||
|
||||
if (!facade->EdgeIsCompressed(ed.id))
|
||||
{
|
||||
BOOST_ASSERT(!facade->EdgeIsCompressed(ed.id));
|
||||
unpacked_path.emplace_back(facade->GetGeometryIndexForEdgeID(ed.id), name_index,
|
||||
turn_instruction, ed.distance, travel_mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<unsigned> id_vector;
|
||||
facade->GetUncompressedGeometry(facade->GetGeometryIndexForEdgeID(ed.id),
|
||||
id_vector);
|
||||
|
||||
const std::size_t start_index =
|
||||
(unpacked_path.empty()
|
||||
? ((start_traversed_in_reverse)
|
||||
? id_vector.size() -
|
||||
phantom_node_pair.source_phantom.fwd_segment_position - 1
|
||||
: phantom_node_pair.source_phantom.fwd_segment_position)
|
||||
: 0);
|
||||
const std::size_t end_index = id_vector.size();
|
||||
|
||||
BOOST_ASSERT(start_index >= 0);
|
||||
BOOST_ASSERT(start_index <= end_index);
|
||||
for (std::size_t i = start_index; i < end_index; ++i)
|
||||
{
|
||||
unpacked_path.emplace_back(id_vector[i], name_index,
|
||||
TurnInstruction::NoTurn, 0, travel_mode);
|
||||
}
|
||||
unpacked_path.back().turn_instruction = turn_instruction;
|
||||
unpacked_path.back().segment_duration = ed.distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SPECIAL_EDGEID != phantom_node_pair.target_phantom.packed_geometry_id)
|
||||
{
|
||||
std::vector<unsigned> id_vector;
|
||||
facade->GetUncompressedGeometry(phantom_node_pair.target_phantom.packed_geometry_id,
|
||||
id_vector);
|
||||
const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
|
||||
phantom_node_pair.target_phantom.packed_geometry_id) &&
|
||||
unpacked_path.empty();
|
||||
|
||||
std::size_t start_index = 0;
|
||||
if (is_local_path)
|
||||
{
|
||||
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
start_index =
|
||||
id_vector.size() - phantom_node_pair.source_phantom.fwd_segment_position;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
if (target_traversed_in_reverse)
|
||||
{
|
||||
std::reverse(id_vector.begin(), id_vector.end());
|
||||
end_index =
|
||||
id_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position;
|
||||
}
|
||||
|
||||
if (start_index > end_index)
|
||||
{
|
||||
start_index = std::min(start_index, id_vector.size() - 1);
|
||||
}
|
||||
|
||||
for (std::size_t i = start_index; i != end_index; (start_index < end_index ? ++i : --i))
|
||||
{
|
||||
BOOST_ASSERT(i < id_vector.size());
|
||||
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
|
||||
unpacked_path.emplace_back(PathData{
|
||||
id_vector[i], phantom_node_pair.target_phantom.name_id, TurnInstruction::NoTurn,
|
||||
0, phantom_node_pair.target_phantom.forward_travel_mode});
|
||||
}
|
||||
}
|
||||
|
||||
// there is no equivalent to a node-based node in an edge-expanded graph.
|
||||
// two equivalent routes may start (or end) at different node-based edges
|
||||
// as they are added with the offset how much "distance" on the edge
|
||||
// has already been traversed. Depending on offset one needs to remove
|
||||
// the last node.
|
||||
if (unpacked_path.size() > 1)
|
||||
{
|
||||
const std::size_t last_index = unpacked_path.size() - 1;
|
||||
const std::size_t second_to_last_index = last_index - 1;
|
||||
|
||||
// looks like a trivially true check but tests for underflow
|
||||
BOOST_ASSERT(last_index > second_to_last_index);
|
||||
|
||||
if (unpacked_path[last_index].node == unpacked_path[second_to_last_index].node)
|
||||
{
|
||||
unpacked_path.pop_back();
|
||||
}
|
||||
BOOST_ASSERT(!unpacked_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> &unpacked_path) const
|
||||
{
|
||||
std::stack<std::pair<NodeID, NodeID>> recursion_stack;
|
||||
recursion_stack.emplace(s, t);
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
edge = recursion_stack.top();
|
||||
recursion_stack.pop();
|
||||
|
||||
EdgeID smaller_edge_id = SPECIAL_EDGEID;
|
||||
int edge_weight = std::numeric_limits<EdgeWeight>::max();
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.first))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.second) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).forward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||
{
|
||||
for (const auto edge_id : facade->GetAdjacentEdgeRange(edge.second))
|
||||
{
|
||||
const int weight = facade->GetEdgeData(edge_id).distance;
|
||||
if ((facade->GetTarget(edge_id) == edge.first) && (weight < edge_weight) &&
|
||||
facade->GetEdgeData(edge_id).backward)
|
||||
{
|
||||
smaller_edge_id = edge_id;
|
||||
edge_weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(edge_weight != std::numeric_limits<EdgeWeight>::max(),
|
||||
"edge weight invalid");
|
||||
|
||||
const EdgeData &ed = facade->GetEdgeData(smaller_edge_id);
|
||||
if (ed.shortcut)
|
||||
{ // unpack
|
||||
const NodeID middle_node_id = ed.id;
|
||||
// again, we need to this in reversed order
|
||||
recursion_stack.emplace(middle_node_id, edge.second);
|
||||
recursion_stack.emplace(edge.first, middle_node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT_MSG(!ed.shortcut, "edge must be shortcut");
|
||||
unpacked_path.emplace_back(edge.first);
|
||||
}
|
||||
}
|
||||
unpacked_path.emplace_back(t);
|
||||
}
|
||||
|
||||
void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
||||
const SearchEngineData::QueryHeap &reverse_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path) const
|
||||
{
|
||||
RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
|
||||
std::reverse(packed_path.begin(), packed_path.end());
|
||||
packed_path.emplace_back(middle_node_id);
|
||||
RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
|
||||
}
|
||||
|
||||
void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
|
||||
const NodeID middle_node_id,
|
||||
std::vector<NodeID> &packed_path) const
|
||||
{
|
||||
NodeID current_node_id = middle_node_id;
|
||||
while (current_node_id != search_heap.GetData(current_node_id).parent)
|
||||
{
|
||||
current_node_id = search_heap.GetData(current_node_id).parent;
|
||||
packed_path.emplace_back(current_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
void Search(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
int &distance,
|
||||
std::vector<NodeID> &packed_leg) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (!forward_heap.Empty())
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset, true);
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset, false);
|
||||
}
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (INVALID_EDGE_WEIGHT == distance || SPECIAL_NODEID == middle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Was a paths over one of the forward/reverse nodes not found?
|
||||
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
|
||||
"no path found");
|
||||
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
}
|
||||
|
||||
// assumes that heaps are already setup correctly.
|
||||
void SearchWithCore(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
SearchEngineData::QueryHeap &forward_core_heap,
|
||||
SearchEngineData::QueryHeap &reverse_core_heap,
|
||||
int &distance,
|
||||
std::vector<NodeID> &packed_leg) const
|
||||
{
|
||||
NodeID middle = SPECIAL_NODEID;
|
||||
|
||||
std::vector<std::pair<NodeID, EdgeWeight>> forward_entry_points;
|
||||
std::vector<std::pair<NodeID, EdgeWeight>> reverse_entry_points;
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
||||
|
||||
// run two-Target Dijkstra routing step.
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (!forward_heap.Empty())
|
||||
{
|
||||
if (facade->IsCoreNode(forward_heap.Min()))
|
||||
{
|
||||
const NodeID node = forward_heap.DeleteMin();
|
||||
const int key = forward_heap.GetKey(node);
|
||||
forward_entry_points.emplace_back(node, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle, distance, min_edge_offset,
|
||||
true);
|
||||
}
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
if (facade->IsCoreNode(reverse_heap.Min()))
|
||||
{
|
||||
const NodeID node = reverse_heap.DeleteMin();
|
||||
const int key = reverse_heap.GetKey(node);
|
||||
reverse_entry_points.emplace_back(node, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle, distance, min_edge_offset,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check if unordered_set might be faster
|
||||
// sort by id and increasing by distance
|
||||
auto entry_point_comparator = [](const std::pair<NodeID, EdgeWeight> &lhs,
|
||||
const std::pair<NodeID, EdgeWeight> &rhs)
|
||||
{
|
||||
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
|
||||
};
|
||||
std::sort(forward_entry_points.begin(), forward_entry_points.end(), entry_point_comparator);
|
||||
std::sort(reverse_entry_points.begin(), reverse_entry_points.end(), entry_point_comparator);
|
||||
|
||||
NodeID last_id = SPECIAL_NODEID;
|
||||
for (const auto p : forward_entry_points)
|
||||
{
|
||||
if (p.first == last_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
forward_core_heap.Insert(p.first, p.second, p.first);
|
||||
last_id = p.first;
|
||||
}
|
||||
last_id = SPECIAL_NODEID;
|
||||
for (const auto p : reverse_entry_points)
|
||||
{
|
||||
if (p.first == last_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
reverse_core_heap.Insert(p.first, p.second, p.first);
|
||||
last_id = p.first;
|
||||
}
|
||||
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
int min_core_edge_offset = 0;
|
||||
if (forward_core_heap.Size() > 0)
|
||||
{
|
||||
min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
|
||||
}
|
||||
if (reverse_core_heap.Size() > 0 && reverse_core_heap.MinKey() < 0)
|
||||
{
|
||||
min_core_edge_offset = std::min(min_core_edge_offset, reverse_core_heap.MinKey());
|
||||
}
|
||||
BOOST_ASSERT(min_core_edge_offset <= 0);
|
||||
|
||||
// run two-target Dijkstra routing step on core with termination criterion
|
||||
while (0 < (forward_core_heap.Size() + reverse_core_heap.Size()) &&
|
||||
distance > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
|
||||
{
|
||||
if (!forward_core_heap.Empty())
|
||||
{
|
||||
RoutingStep(forward_core_heap, reverse_core_heap, middle, distance,
|
||||
min_core_edge_offset, true, false);
|
||||
}
|
||||
if (!reverse_core_heap.Empty())
|
||||
{
|
||||
RoutingStep(reverse_core_heap, forward_core_heap, middle, distance,
|
||||
min_core_edge_offset, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (INVALID_EDGE_WEIGHT == distance || SPECIAL_NODEID == middle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Was a paths over one of the forward/reverse nodes not found?
|
||||
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != distance),
|
||||
"no path found");
|
||||
|
||||
// we need to unpack sub path from core heaps
|
||||
if (facade->IsCoreNode(middle))
|
||||
{
|
||||
std::vector<NodeID> packed_core_leg;
|
||||
RetrievePackedPathFromHeap(forward_core_heap, reverse_core_heap, middle,
|
||||
packed_core_leg);
|
||||
BOOST_ASSERT(packed_core_leg.size() > 0);
|
||||
RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
|
||||
std::reverse(packed_leg.begin(), packed_leg.end());
|
||||
packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
|
||||
RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
|
||||
}
|
||||
else
|
||||
{
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
||||
}
|
||||
}
|
||||
|
||||
double get_network_distance(SearchEngineData::QueryHeap &forward_heap,
|
||||
SearchEngineData::QueryHeap &reverse_heap,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom) const
|
||||
{
|
||||
EdgeWeight upper_bound = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
EdgeWeight edge_offset = std::min(0, -source_phantom.GetForwardWeightPlusOffset());
|
||||
edge_offset = std::min(edge_offset, -source_phantom.GetReverseWeightPlusOffset());
|
||||
|
||||
if (source_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_node_id,
|
||||
-source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_node_id);
|
||||
}
|
||||
if (source_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_node_id,
|
||||
-source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
if (target_phantom.forward_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.forward_node_id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_node_id);
|
||||
}
|
||||
if (target_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.reverse_node_id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// search from s and t till new_min/(1+epsilon) > length_of_shortest_path
|
||||
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
||||
{
|
||||
if (0 < forward_heap.Size())
|
||||
{
|
||||
RoutingStep(forward_heap, reverse_heap, middle_node, upper_bound, edge_offset,
|
||||
true);
|
||||
}
|
||||
if (0 < reverse_heap.Size())
|
||||
{
|
||||
RoutingStep(reverse_heap, forward_heap, middle_node, upper_bound, edge_offset,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
double distance = std::numeric_limits<double>::max();
|
||||
if (upper_bound != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
std::vector<NodeID> packed_leg;
|
||||
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle_node, packed_leg);
|
||||
std::vector<PathData> unpacked_path;
|
||||
PhantomNodes nodes;
|
||||
nodes.source_phantom = source_phantom;
|
||||
nodes.target_phantom = target_phantom;
|
||||
UnpackPath(packed_leg.begin(), packed_leg.end(), nodes, unpacked_path);
|
||||
|
||||
FixedPointCoordinate previous_coordinate = source_phantom.location;
|
||||
FixedPointCoordinate current_coordinate;
|
||||
distance = 0;
|
||||
for (const auto &p : unpacked_path)
|
||||
{
|
||||
current_coordinate = facade->GetCoordinateOfNode(p.node);
|
||||
distance += coordinate_calculation::haversine_distance(previous_coordinate,
|
||||
current_coordinate);
|
||||
previous_coordinate = current_coordinate;
|
||||
}
|
||||
distance += coordinate_calculation::haversine_distance(previous_coordinate,
|
||||
target_phantom.location);
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ROUTING_BASE_HPP
|
||||
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SHORTEST_PATH_HPP
|
||||
#define SHORTEST_PATH_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include "routing_base.hpp"
|
||||
|
||||
#include "../data_structures/search_engine_data.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
template <class DataFacadeT>
|
||||
class ShortestPathRouting final
|
||||
: public BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>
|
||||
{
|
||||
using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
|
||||
using QueryHeap = SearchEngineData::QueryHeap;
|
||||
SearchEngineData &engine_working_data;
|
||||
|
||||
public:
|
||||
ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
||||
: super(facade), engine_working_data(engine_working_data)
|
||||
{
|
||||
}
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
// allows a uturn at the target_phantom
|
||||
// searches source forward/reverse -> target forward/reverse
|
||||
void SearchWithUTurn(QueryHeap &forward_heap,
|
||||
QueryHeap &reverse_heap,
|
||||
const bool search_from_forward_node,
|
||||
const bool search_from_reverse_node,
|
||||
const bool search_to_forward_node,
|
||||
const bool search_to_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_distance_to_forward,
|
||||
const int total_distance_to_reverse,
|
||||
int &new_total_distance,
|
||||
std::vector<NodeID> &leg_packed_path) const
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_node_id,
|
||||
total_distance_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_node_id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_node_id,
|
||||
total_distance_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_node_id);
|
||||
}
|
||||
if (search_to_forward_node)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.forward_node_id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_node_id);
|
||||
}
|
||||
if (search_to_reverse_node)
|
||||
{
|
||||
reverse_heap.Insert(target_phantom.reverse_node_id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_node_id);
|
||||
}
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path);
|
||||
}
|
||||
|
||||
// If source and target are reverse on a oneway we need to find a path
|
||||
// that connects the two. This is _not_ the shortest path in our model,
|
||||
// as source and target are on the same edge based node.
|
||||
// We force a detour by inserting "virtaul vias", which means we search a path
|
||||
// from all nodes that are connected by outgoing edges to all nodes that are connected by
|
||||
// incoming edges.
|
||||
// ------^
|
||||
// | ^source
|
||||
// | ^
|
||||
// | ^target
|
||||
// ------^
|
||||
void SearchLoop(QueryHeap &forward_heap,
|
||||
QueryHeap &reverse_heap,
|
||||
const bool search_forward_node,
|
||||
const bool search_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_distance_to_forward,
|
||||
const int total_distance_to_reverse,
|
||||
int &new_total_distance_to_forward,
|
||||
int &new_total_distance_to_reverse,
|
||||
std::vector<NodeID> &leg_packed_path_forward,
|
||||
std::vector<NodeID> &leg_packed_path_reverse) const
|
||||
{
|
||||
BOOST_ASSERT(source_phantom.forward_node_id == target_phantom.forward_node_id);
|
||||
BOOST_ASSERT(source_phantom.reverse_node_id == target_phantom.reverse_node_id);
|
||||
|
||||
if (search_forward_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
auto node_id = source_phantom.forward_node_id;
|
||||
|
||||
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
||||
{
|
||||
const auto& data = super::facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = total_distance_to_forward + data.distance - source_phantom.GetForwardWeightPlusOffset();
|
||||
forward_heap.Insert(target, offset, target);
|
||||
}
|
||||
|
||||
if (data.backward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = data.distance + target_phantom.GetForwardWeightPlusOffset();
|
||||
reverse_heap.Insert(target, offset, target);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
||||
leg_packed_path_forward);
|
||||
|
||||
// insert node to both endpoints to close the leg
|
||||
leg_packed_path_forward.push_back(node_id);
|
||||
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
||||
leg_packed_path_forward.push_back(node_id);
|
||||
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
||||
}
|
||||
|
||||
if (search_reverse_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
auto node_id = source_phantom.reverse_node_id;
|
||||
|
||||
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
||||
{
|
||||
const auto& data = super::facade->GetEdgeData(edge);
|
||||
if (data.forward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = total_distance_to_reverse + data.distance - source_phantom.GetReverseWeightPlusOffset();
|
||||
forward_heap.Insert(target, offset, target);
|
||||
}
|
||||
|
||||
if (data.backward)
|
||||
{
|
||||
auto target = super::facade->GetTarget(edge);
|
||||
auto offset = data.distance + target_phantom.GetReverseWeightPlusOffset();
|
||||
reverse_heap.Insert(target, offset, target);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
||||
leg_packed_path_reverse);
|
||||
|
||||
// insert node to both endpoints to close the leg
|
||||
leg_packed_path_reverse.push_back(node_id);
|
||||
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
||||
leg_packed_path_reverse.push_back(node_id);
|
||||
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// searches shortest path between:
|
||||
// source forward/reverse -> target forward
|
||||
// source forward/reverse -> target reverse
|
||||
void Search(QueryHeap &forward_heap,
|
||||
QueryHeap &reverse_heap,
|
||||
const bool search_from_forward_node,
|
||||
const bool search_from_reverse_node,
|
||||
const bool search_to_forward_node,
|
||||
const bool search_to_reverse_node,
|
||||
const PhantomNode &source_phantom,
|
||||
const PhantomNode &target_phantom,
|
||||
const int total_distance_to_forward,
|
||||
const int total_distance_to_reverse,
|
||||
int &new_total_distance_to_forward,
|
||||
int &new_total_distance_to_reverse,
|
||||
std::vector<NodeID> &leg_packed_path_forward,
|
||||
std::vector<NodeID> &leg_packed_path_reverse) const
|
||||
{
|
||||
if (search_to_forward_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
reverse_heap.Insert(target_phantom.forward_node_id,
|
||||
target_phantom.GetForwardWeightPlusOffset(),
|
||||
target_phantom.forward_node_id);
|
||||
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_node_id,
|
||||
total_distance_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_node_id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_node_id,
|
||||
total_distance_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_node_id);
|
||||
}
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
||||
leg_packed_path_forward);
|
||||
}
|
||||
|
||||
if (search_to_reverse_node)
|
||||
{
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
reverse_heap.Insert(target_phantom.reverse_node_id,
|
||||
target_phantom.GetReverseWeightPlusOffset(),
|
||||
target_phantom.reverse_node_id);
|
||||
if (search_from_forward_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.forward_node_id,
|
||||
total_distance_to_forward -
|
||||
source_phantom.GetForwardWeightPlusOffset(),
|
||||
source_phantom.forward_node_id);
|
||||
}
|
||||
if (search_from_reverse_node)
|
||||
{
|
||||
forward_heap.Insert(source_phantom.reverse_node_id,
|
||||
total_distance_to_reverse -
|
||||
source_phantom.GetReverseWeightPlusOffset(),
|
||||
source_phantom.reverse_node_id);
|
||||
}
|
||||
BOOST_ASSERT(forward_heap.Size() > 0);
|
||||
BOOST_ASSERT(reverse_heap.Size() > 0);
|
||||
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
||||
leg_packed_path_reverse);
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackLegs(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<NodeID> &total_packed_path,
|
||||
const std::vector<std::size_t> &packed_leg_begin,
|
||||
const int shortest_path_length,
|
||||
InternalRouteResult &raw_route_data) const
|
||||
{
|
||||
raw_route_data.unpacked_path_segments.resize(packed_leg_begin.size() - 1);
|
||||
|
||||
raw_route_data.shortest_path_length = shortest_path_length;
|
||||
|
||||
for (const auto current_leg : osrm::irange<std::size_t>(0, packed_leg_begin.size() - 1))
|
||||
{
|
||||
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
|
||||
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
|
||||
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
|
||||
super::UnpackPath(leg_begin, leg_end, unpack_phantom_node_pair,
|
||||
raw_route_data.unpacked_path_segments[current_leg]);
|
||||
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_node_id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(*std::prev(leg_end) !=
|
||||
phantom_nodes_vector[current_leg].target_phantom.forward_node_id));
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<bool> &uturn_indicators,
|
||||
InternalRouteResult &raw_route_data) const
|
||||
{
|
||||
BOOST_ASSERT(uturn_indicators.size() == phantom_nodes_vector.size() + 1);
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
||||
super::facade->GetNumberOfNodes());
|
||||
|
||||
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
|
||||
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
|
||||
|
||||
int total_distance_to_forward = 0;
|
||||
int total_distance_to_reverse = 0;
|
||||
bool search_from_forward_node = phantom_nodes_vector.front().source_phantom.forward_node_id != SPECIAL_NODEID;
|
||||
bool search_from_reverse_node = phantom_nodes_vector.front().source_phantom.reverse_node_id != SPECIAL_NODEID;
|
||||
|
||||
std::vector<NodeID> prev_packed_leg_to_forward;
|
||||
std::vector<NodeID> prev_packed_leg_to_reverse;
|
||||
|
||||
std::vector<NodeID> total_packed_path_to_forward;
|
||||
std::vector<std::size_t> packed_leg_to_forward_begin;
|
||||
std::vector<NodeID> total_packed_path_to_reverse;
|
||||
std::vector<std::size_t> packed_leg_to_reverse_begin;
|
||||
|
||||
std::size_t current_leg = 0;
|
||||
// this implements a dynamic program that finds the shortest route through
|
||||
// a list of vias
|
||||
for (const auto &phantom_node_pair : phantom_nodes_vector)
|
||||
{
|
||||
int new_total_distance_to_forward = INVALID_EDGE_WEIGHT;
|
||||
int new_total_distance_to_reverse = INVALID_EDGE_WEIGHT;
|
||||
|
||||
std::vector<NodeID> packed_leg_to_forward;
|
||||
std::vector<NodeID> packed_leg_to_reverse;
|
||||
|
||||
const auto &source_phantom = phantom_node_pair.source_phantom;
|
||||
const auto &target_phantom = phantom_node_pair.target_phantom;
|
||||
|
||||
|
||||
BOOST_ASSERT(current_leg + 1 < uturn_indicators.size());
|
||||
const bool allow_u_turn_at_via = uturn_indicators[current_leg + 1];
|
||||
|
||||
bool search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
||||
bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
||||
|
||||
BOOST_ASSERT(!search_from_forward_node || source_phantom.forward_node_id != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(!search_from_reverse_node || source_phantom.reverse_node_id != SPECIAL_NODEID);
|
||||
|
||||
if (source_phantom.forward_node_id == target_phantom.forward_node_id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||
{
|
||||
search_to_forward_node = search_from_reverse_node;
|
||||
}
|
||||
if (source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() > target_phantom.GetReverseWeightPlusOffset())
|
||||
{
|
||||
search_to_reverse_node = search_from_forward_node;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(search_from_forward_node || search_from_reverse_node);
|
||||
|
||||
if(search_to_reverse_node || search_to_forward_node)
|
||||
{
|
||||
if (allow_u_turn_at_via)
|
||||
{
|
||||
SearchWithUTurn(forward_heap, reverse_heap, search_from_forward_node,
|
||||
search_from_reverse_node, search_to_forward_node,
|
||||
search_to_reverse_node, source_phantom, target_phantom,
|
||||
total_distance_to_forward, total_distance_to_reverse,
|
||||
new_total_distance_to_forward, packed_leg_to_forward);
|
||||
// if only the reverse node is valid (e.g. when using the match plugin) we actually need to move
|
||||
if (target_phantom.forward_node_id == SPECIAL_NODEID)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
|
||||
new_total_distance_to_reverse = new_total_distance_to_forward;
|
||||
packed_leg_to_reverse = std::move(packed_leg_to_forward);
|
||||
new_total_distance_to_forward = INVALID_EDGE_WEIGHT;
|
||||
}
|
||||
else if (target_phantom.reverse_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
new_total_distance_to_reverse = new_total_distance_to_forward;
|
||||
packed_leg_to_reverse = packed_leg_to_forward;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Search(forward_heap, reverse_heap, search_from_forward_node,
|
||||
search_from_reverse_node, search_to_forward_node, search_to_reverse_node,
|
||||
source_phantom, target_phantom, total_distance_to_forward,
|
||||
total_distance_to_reverse, new_total_distance_to_forward,
|
||||
new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
||||
search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
||||
BOOST_ASSERT(search_from_reverse_node == search_to_reverse_node);
|
||||
BOOST_ASSERT(search_from_forward_node == search_to_forward_node);
|
||||
SearchLoop(forward_heap, reverse_heap, search_from_forward_node,
|
||||
search_from_reverse_node, source_phantom, target_phantom, total_distance_to_forward,
|
||||
total_distance_to_reverse, new_total_distance_to_forward,
|
||||
new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
|
||||
}
|
||||
|
||||
// No path found for both target nodes?
|
||||
if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) &&
|
||||
(INVALID_EDGE_WEIGHT == new_total_distance_to_reverse))
|
||||
{
|
||||
raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
|
||||
raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to figure out how the new legs connect to the previous ones
|
||||
if (current_leg > 0)
|
||||
{
|
||||
bool forward_to_forward =
|
||||
(new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_forward.front() == source_phantom.forward_node_id;
|
||||
bool reverse_to_forward =
|
||||
(new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_forward.front() == source_phantom.reverse_node_id;
|
||||
bool forward_to_reverse =
|
||||
(new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_reverse.front() == source_phantom.forward_node_id;
|
||||
bool reverse_to_reverse =
|
||||
(new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
|
||||
packed_leg_to_reverse.front() == source_phantom.reverse_node_id;
|
||||
|
||||
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
|
||||
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
|
||||
|
||||
// in this case we always need to copy
|
||||
if (forward_to_forward && forward_to_reverse)
|
||||
{
|
||||
// in this case we copy the path leading to the source forward node
|
||||
// and change the case
|
||||
total_packed_path_to_reverse = total_packed_path_to_forward;
|
||||
packed_leg_to_reverse_begin = packed_leg_to_forward_begin;
|
||||
forward_to_reverse = false;
|
||||
reverse_to_reverse = true;
|
||||
}
|
||||
else if (reverse_to_forward && reverse_to_reverse)
|
||||
{
|
||||
total_packed_path_to_forward = total_packed_path_to_reverse;
|
||||
packed_leg_to_forward_begin = packed_leg_to_reverse_begin;
|
||||
reverse_to_forward = false;
|
||||
forward_to_forward = true;
|
||||
}
|
||||
BOOST_ASSERT(!forward_to_forward || !forward_to_reverse);
|
||||
BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse);
|
||||
|
||||
// in this case we just need to swap to regain the correct mapping
|
||||
if (reverse_to_forward || forward_to_reverse)
|
||||
{
|
||||
total_packed_path_to_forward.swap(total_packed_path_to_reverse);
|
||||
packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_total_distance_to_forward != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.forward_node_id != SPECIAL_NODEID);
|
||||
|
||||
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
||||
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
|
||||
packed_leg_to_forward.begin(),
|
||||
packed_leg_to_forward.end());
|
||||
search_from_forward_node = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_packed_path_to_forward.clear();
|
||||
packed_leg_to_forward_begin.clear();
|
||||
search_from_forward_node = false;
|
||||
}
|
||||
|
||||
if (new_total_distance_to_reverse != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
|
||||
|
||||
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
||||
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
|
||||
packed_leg_to_reverse.begin(),
|
||||
packed_leg_to_reverse.end());
|
||||
search_from_reverse_node = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_packed_path_to_reverse.clear();
|
||||
packed_leg_to_reverse_begin.clear();
|
||||
search_from_reverse_node = false;
|
||||
}
|
||||
|
||||
prev_packed_leg_to_forward = std::move(packed_leg_to_forward);
|
||||
prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse);
|
||||
|
||||
total_distance_to_forward = new_total_distance_to_forward;
|
||||
total_distance_to_reverse = new_total_distance_to_reverse;
|
||||
|
||||
++current_leg;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(total_distance_to_forward != INVALID_EDGE_WEIGHT ||
|
||||
total_distance_to_reverse != INVALID_EDGE_WEIGHT);
|
||||
|
||||
// We make sure the fastest route is always in packed_legs_to_forward
|
||||
if (total_distance_to_forward > total_distance_to_reverse)
|
||||
{
|
||||
// insert sentinel
|
||||
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
||||
BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1);
|
||||
|
||||
UnpackLegs(phantom_nodes_vector, total_packed_path_to_reverse,
|
||||
packed_leg_to_reverse_begin, total_distance_to_reverse, raw_route_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// insert sentinel
|
||||
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
||||
BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1);
|
||||
|
||||
UnpackLegs(phantom_nodes_vector, total_packed_path_to_forward,
|
||||
packed_leg_to_forward_begin, total_distance_to_forward, raw_route_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHORTEST_PATH_HPP */
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEARCH_ENGINE_HPP
|
||||
#define SEARCH_ENGINE_HPP
|
||||
|
||||
#include "search_engine_data.hpp"
|
||||
#include "../routing_algorithms/alternative_path.hpp"
|
||||
#include "../routing_algorithms/many_to_many.hpp"
|
||||
#include "../routing_algorithms/map_matching.hpp"
|
||||
#include "../routing_algorithms/shortest_path.hpp"
|
||||
#include "../routing_algorithms/direct_shortest_path.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <class DataFacadeT> class SearchEngine
|
||||
{
|
||||
private:
|
||||
DataFacadeT *facade;
|
||||
SearchEngineData engine_working_data;
|
||||
|
||||
public:
|
||||
ShortestPathRouting<DataFacadeT> shortest_path;
|
||||
DirectShortestPathRouting<DataFacadeT> direct_shortest_path;
|
||||
AlternativeRouting<DataFacadeT> alternative_path;
|
||||
ManyToManyRouting<DataFacadeT> distance_table;
|
||||
MapMatching<DataFacadeT> map_matching;
|
||||
|
||||
explicit SearchEngine(DataFacadeT *facade)
|
||||
: facade(facade),
|
||||
shortest_path(facade, engine_working_data),
|
||||
direct_shortest_path(facade, engine_working_data),
|
||||
alternative_path(facade, engine_working_data),
|
||||
distance_table(facade, engine_working_data),
|
||||
map_matching(facade, engine_working_data)
|
||||
{
|
||||
static_assert(!std::is_pointer<DataFacadeT>::value, "don't instantiate with ptr type");
|
||||
static_assert(std::is_object<DataFacadeT>::value,
|
||||
"don't instantiate with void, function, or reference");
|
||||
}
|
||||
|
||||
~SearchEngine() {}
|
||||
};
|
||||
|
||||
#endif // SEARCH_ENGINE_HPP
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEARCH_ENGINE_DATA_HPP
|
||||
#define SEARCH_ENGINE_DATA_HPP
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "binary_heap.hpp"
|
||||
|
||||
struct HeapData
|
||||
{
|
||||
NodeID parent;
|
||||
/* explicit */ HeapData(NodeID p) : parent(p) {}
|
||||
};
|
||||
|
||||
struct SearchEngineData
|
||||
{
|
||||
using QueryHeap = BinaryHeap<NodeID, NodeID, int, HeapData, UnorderedMapStorage<NodeID, int>>;
|
||||
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
||||
|
||||
static SearchEngineHeapPtr forward_heap_1;
|
||||
static SearchEngineHeapPtr reverse_heap_1;
|
||||
static SearchEngineHeapPtr forward_heap_2;
|
||||
static SearchEngineHeapPtr reverse_heap_2;
|
||||
static SearchEngineHeapPtr forward_heap_3;
|
||||
static SearchEngineHeapPtr reverse_heap_3;
|
||||
|
||||
void InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes);
|
||||
|
||||
void InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes);
|
||||
|
||||
void InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes);
|
||||
};
|
||||
|
||||
#endif // SEARCH_ENGINE_DATA_HPP
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEGMENT_INFORMATION_HPP
|
||||
#define SEGMENT_INFORMATION_HPP
|
||||
|
||||
#include "turn_instructions.hpp"
|
||||
|
||||
#include "../data_structures/travel_mode.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
#include <utility>
|
||||
|
||||
// Struct fits everything in one cache line
|
||||
struct SegmentInformation
|
||||
{
|
||||
FixedPointCoordinate location;
|
||||
NodeID name_id;
|
||||
EdgeWeight duration;
|
||||
float length;
|
||||
short pre_turn_bearing; // more than enough [0..3600] fits into 12 bits
|
||||
short post_turn_bearing;
|
||||
TurnInstruction turn_instruction;
|
||||
TravelMode travel_mode;
|
||||
bool necessary;
|
||||
bool is_via_location;
|
||||
|
||||
explicit SegmentInformation(FixedPointCoordinate location,
|
||||
const NodeID name_id,
|
||||
const EdgeWeight duration,
|
||||
const float length,
|
||||
const TurnInstruction turn_instruction,
|
||||
const bool necessary,
|
||||
const bool is_via_location,
|
||||
const TravelMode travel_mode)
|
||||
: location(std::move(location)), name_id(name_id), duration(duration), length(length),
|
||||
pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction), travel_mode(travel_mode),
|
||||
necessary(necessary), is_via_location(is_via_location)
|
||||
{
|
||||
}
|
||||
|
||||
explicit SegmentInformation(FixedPointCoordinate location,
|
||||
const NodeID name_id,
|
||||
const EdgeWeight duration,
|
||||
const float length,
|
||||
const TurnInstruction turn_instruction,
|
||||
const TravelMode travel_mode)
|
||||
: location(std::move(location)), name_id(name_id), duration(duration), length(length),
|
||||
pre_turn_bearing(0), post_turn_bearing(0), turn_instruction(turn_instruction), travel_mode(travel_mode),
|
||||
necessary(turn_instruction != TurnInstruction::NoTurn), is_via_location(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SEGMENT_INFORMATION_HPP */
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TRIP_BRUTE_FORCE_HPP
|
||||
#define TRIP_BRUTE_FORCE_HPP
|
||||
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../util/dist_table_wrapper.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace trip
|
||||
{
|
||||
|
||||
// computes the distance of a given permutation
|
||||
EdgeWeight ReturnDistance(const DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const std::vector<NodeID> &location_order,
|
||||
const EdgeWeight min_route_dist,
|
||||
const std::size_t component_size)
|
||||
{
|
||||
EdgeWeight route_dist = 0;
|
||||
std::size_t i = 0;
|
||||
while (i < location_order.size() && (route_dist < min_route_dist))
|
||||
{
|
||||
route_dist += dist_table(location_order[i], location_order[(i + 1) % component_size]);
|
||||
BOOST_ASSERT_MSG(dist_table(location_order[i], location_order[(i + 1) % component_size]) !=
|
||||
INVALID_EDGE_WEIGHT,
|
||||
"invalid route found");
|
||||
++i;
|
||||
}
|
||||
|
||||
return route_dist;
|
||||
}
|
||||
|
||||
// computes the route by computing all permutations and selecting the shortest
|
||||
template <typename NodeIDIterator>
|
||||
std::vector<NodeID> BruteForceTrip(const NodeIDIterator start,
|
||||
const NodeIDIterator end,
|
||||
const std::size_t number_of_locations,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table)
|
||||
{
|
||||
(void)number_of_locations; // unused
|
||||
|
||||
const auto component_size = std::distance(start, end);
|
||||
|
||||
std::vector<NodeID> perm(start, end);
|
||||
std::vector<NodeID> route;
|
||||
route.reserve(component_size);
|
||||
|
||||
EdgeWeight min_route_dist = INVALID_EDGE_WEIGHT;
|
||||
|
||||
// check length of all possible permutation of the component ids
|
||||
|
||||
BOOST_ASSERT_MSG(perm.size() > 0, "no permutation given");
|
||||
BOOST_ASSERT_MSG(*(std::max_element(std::begin(perm), std::end(perm))) < number_of_locations,
|
||||
"invalid node id");
|
||||
BOOST_ASSERT_MSG(*(std::min_element(std::begin(perm), std::end(perm))) >= 0, "invalid node id");
|
||||
|
||||
do
|
||||
{
|
||||
const auto new_distance = ReturnDistance(dist_table, perm, min_route_dist, component_size);
|
||||
if (new_distance <= min_route_dist)
|
||||
{
|
||||
min_route_dist = new_distance;
|
||||
route = perm;
|
||||
}
|
||||
} while (std::next_permutation(std::begin(perm), std::end(perm)));
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
} // end namespace trip
|
||||
} // end namespace osrm
|
||||
#endif // TRIP_BRUTE_FORCE_HPP
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TRIP_FARTHEST_INSERTION_HPP
|
||||
#define TRIP_FARTHEST_INSERTION_HPP
|
||||
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../util/dist_table_wrapper.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace trip
|
||||
{
|
||||
|
||||
// given a route and a new location, find the best place of insertion and
|
||||
// check the distance of roundtrip when the new location is additionally visited
|
||||
using NodeIDIter = std::vector<NodeID>::iterator;
|
||||
std::pair<EdgeWeight, NodeIDIter>
|
||||
GetShortestRoundTrip(const NodeID new_loc,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const std::size_t number_of_locations,
|
||||
std::vector<NodeID> &route)
|
||||
{
|
||||
(void)number_of_locations; // unused
|
||||
|
||||
auto min_trip_distance = INVALID_EDGE_WEIGHT;
|
||||
NodeIDIter next_insert_point_candidate;
|
||||
|
||||
// for all nodes in the current trip find the best insertion resulting in the shortest path
|
||||
// assert min 2 nodes in route
|
||||
const auto start = std::begin(route);
|
||||
const auto end = std::end(route);
|
||||
for (auto from_node = start; from_node != end; ++from_node)
|
||||
{
|
||||
auto to_node = std::next(from_node);
|
||||
if (to_node == end)
|
||||
{
|
||||
to_node = start;
|
||||
}
|
||||
|
||||
const auto dist_from = dist_table(*from_node, new_loc);
|
||||
const auto dist_to = dist_table(new_loc, *to_node);
|
||||
const auto trip_dist = dist_from + dist_to - dist_table(*from_node, *to_node);
|
||||
|
||||
BOOST_ASSERT_MSG(dist_from != INVALID_EDGE_WEIGHT, "distance has invalid edge weight");
|
||||
BOOST_ASSERT_MSG(dist_to != INVALID_EDGE_WEIGHT, "distance has invalid edge weight");
|
||||
// This is not neccessarily true:
|
||||
// Lets say you have an edge (u, v) with duration 100. If you place a coordinate exactly in
|
||||
// the middle of the segment yielding (u, v'), the adjusted duration will be 100 * 0.5 = 50.
|
||||
// Now imagine two coordinates. One placed at 0.99 and one at 0.999. This means (u, v') now
|
||||
// has a duration of 100 * 0.99 = 99, but (u, v'') also has a duration of 100 * 0.995 = 99.
|
||||
// In which case (v', v'') has a duration of 0.
|
||||
// BOOST_ASSERT_MSG(trip_dist >= 0, "previous trip was not minimal. something's wrong");
|
||||
|
||||
// from all possible insertions to the current trip, choose the shortest of all insertions
|
||||
if (trip_dist < min_trip_distance)
|
||||
{
|
||||
min_trip_distance = trip_dist;
|
||||
next_insert_point_candidate = to_node;
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT_MSG(min_trip_distance != INVALID_EDGE_WEIGHT, "trip has invalid edge weight");
|
||||
|
||||
return std::make_pair(min_trip_distance, next_insert_point_candidate);
|
||||
}
|
||||
|
||||
template <typename NodeIDIterator>
|
||||
// given two initial start nodes, find a roundtrip route using the farthest insertion algorithm
|
||||
std::vector<NodeID> FindRoute(const std::size_t &number_of_locations,
|
||||
const std::size_t &component_size,
|
||||
const NodeIDIterator &start,
|
||||
const NodeIDIterator &end,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table,
|
||||
const NodeID &start1,
|
||||
const NodeID &start2)
|
||||
{
|
||||
BOOST_ASSERT_MSG(number_of_locations >= component_size,
|
||||
"component size bigger than total number of locations");
|
||||
|
||||
std::vector<NodeID> route;
|
||||
route.reserve(number_of_locations);
|
||||
|
||||
// tracks which nodes have been already visited
|
||||
std::vector<bool> visited(number_of_locations, false);
|
||||
|
||||
visited[start1] = true;
|
||||
visited[start2] = true;
|
||||
route.push_back(start1);
|
||||
route.push_back(start2);
|
||||
|
||||
// add all other nodes missing (two nodes are already in the initial start trip)
|
||||
for (std::size_t j = 2; j < component_size; ++j)
|
||||
{
|
||||
|
||||
auto farthest_distance = std::numeric_limits<int>::min();
|
||||
auto next_node = -1;
|
||||
NodeIDIter next_insert_point;
|
||||
|
||||
// find unvisited loc i that is the farthest away from all other visited locs
|
||||
for (auto i = start; i != end; ++i)
|
||||
{
|
||||
// find the shortest distance from i to all visited nodes
|
||||
if (!visited[*i])
|
||||
{
|
||||
const auto insert_candidate =
|
||||
GetShortestRoundTrip(*i, dist_table, number_of_locations, route);
|
||||
|
||||
BOOST_ASSERT_MSG(insert_candidate.first != INVALID_EDGE_WEIGHT,
|
||||
"shortest round trip is invalid");
|
||||
|
||||
// add the location to the current trip such that it results in the shortest total
|
||||
// tour
|
||||
if (insert_candidate.first >= farthest_distance)
|
||||
{
|
||||
farthest_distance = insert_candidate.first;
|
||||
next_node = *i;
|
||||
next_insert_point = insert_candidate.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(next_node >= 0, "next node to visit is invalid");
|
||||
|
||||
// mark as visited and insert node
|
||||
visited[next_node] = true;
|
||||
route.insert(next_insert_point, next_node);
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
template <typename NodeIDIterator>
|
||||
std::vector<NodeID> FarthestInsertionTrip(const NodeIDIterator &start,
|
||||
const NodeIDIterator &end,
|
||||
const std::size_t number_of_locations,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// START FARTHEST INSERTION HERE
|
||||
// 1. start at a random round trip of 2 locations
|
||||
// 2. find the location that is the farthest away from the visited locations and whose insertion
|
||||
// will make the round trip the longest
|
||||
// 3. add the found location to the current round trip such that round trip is the shortest
|
||||
// 4. repeat 2-3 until all locations are visited
|
||||
// 5. DONE!
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const auto component_size = std::distance(start, end);
|
||||
BOOST_ASSERT(component_size >= 0);
|
||||
|
||||
auto max_from = -1;
|
||||
auto max_to = -1;
|
||||
|
||||
if (static_cast<std::size_t>(component_size) == number_of_locations)
|
||||
{
|
||||
// find the pair of location with the biggest distance and make the pair the initial start
|
||||
// trip
|
||||
const auto index = std::distance(
|
||||
std::begin(dist_table), std::max_element(std::begin(dist_table), std::end(dist_table)));
|
||||
max_from = index / number_of_locations;
|
||||
max_to = index % number_of_locations;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto max_dist = 0;
|
||||
for (auto x = start; x != end; ++x)
|
||||
{
|
||||
for (auto y = start; y != end; ++y)
|
||||
{
|
||||
const auto xy_dist = dist_table(*x, *y);
|
||||
if (xy_dist > max_dist)
|
||||
{
|
||||
max_dist = xy_dist;
|
||||
max_from = *x;
|
||||
max_to = *y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(max_from >= 0);
|
||||
BOOST_ASSERT(max_to >= 0);
|
||||
BOOST_ASSERT_MSG(static_cast<std::size_t>(max_from) < number_of_locations, "start node");
|
||||
BOOST_ASSERT_MSG(static_cast<std::size_t>(max_to) < number_of_locations, "start node");
|
||||
return FindRoute(number_of_locations, component_size, start, end, dist_table, max_from, max_to);
|
||||
}
|
||||
|
||||
} // end namespace trip
|
||||
} // end namespace osrm
|
||||
|
||||
#endif // TRIP_FARTHEST_INSERTION_HPP
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TRIP_NEAREST_NEIGHBOUR_HPP
|
||||
#define TRIP_NEAREST_NEIGHBOUR_HPP
|
||||
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
#include "../util/dist_table_wrapper.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace trip
|
||||
{
|
||||
template <typename NodeIDIterator>
|
||||
std::vector<NodeID> NearestNeighbourTrip(const NodeIDIterator &start,
|
||||
const NodeIDIterator &end,
|
||||
const std::size_t number_of_locations,
|
||||
const DistTableWrapper<EdgeWeight> &dist_table)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// START GREEDY NEAREST NEIGHBOUR HERE
|
||||
// 1. grab a random location and mark as starting point
|
||||
// 2. find the nearest unvisited neighbour, set it as the current location and mark as visited
|
||||
// 3. repeat 2 until there is no unvisited location
|
||||
// 4. return route back to starting point
|
||||
// 5. compute route
|
||||
// 6. repeat 1-5 with different starting points and choose iteration with shortest trip
|
||||
// 7. DONE!
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector<NodeID> route;
|
||||
route.reserve(number_of_locations);
|
||||
|
||||
const auto component_size = std::distance(start, end);
|
||||
auto shortest_trip_distance = INVALID_EDGE_WEIGHT;
|
||||
|
||||
// ALWAYS START AT ANOTHER STARTING POINT
|
||||
for (auto start_node = start; start_node != end; ++start_node)
|
||||
{
|
||||
NodeID curr_node = *start_node;
|
||||
|
||||
std::vector<NodeID> curr_route;
|
||||
curr_route.reserve(component_size);
|
||||
curr_route.push_back(*start_node);
|
||||
|
||||
// visited[i] indicates whether node i was already visited by the salesman
|
||||
std::vector<bool> visited(number_of_locations, false);
|
||||
visited[*start_node] = true;
|
||||
|
||||
// 3. REPEAT FOR EVERY UNVISITED NODE
|
||||
EdgeWeight trip_dist = 0;
|
||||
for (std::size_t via_point = 1; via_point < component_size; ++via_point)
|
||||
{
|
||||
EdgeWeight min_dist = INVALID_EDGE_WEIGHT;
|
||||
NodeID min_id = SPECIAL_NODEID;
|
||||
|
||||
// 2. FIND NEAREST NEIGHBOUR
|
||||
for (auto next = start; next != end; ++next)
|
||||
{
|
||||
const auto curr_dist = dist_table(curr_node, *next);
|
||||
BOOST_ASSERT_MSG(curr_dist != INVALID_EDGE_WEIGHT, "invalid distance found");
|
||||
if (!visited[*next] && curr_dist < min_dist)
|
||||
{
|
||||
min_dist = curr_dist;
|
||||
min_id = *next;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(min_id != SPECIAL_NODEID, "no next node found");
|
||||
|
||||
visited[min_id] = true;
|
||||
curr_route.push_back(min_id);
|
||||
trip_dist += min_dist;
|
||||
curr_node = min_id;
|
||||
}
|
||||
|
||||
// check round trip with this starting point is shorter than the shortest round trip found
|
||||
// till now
|
||||
if (trip_dist < shortest_trip_distance)
|
||||
{
|
||||
shortest_trip_distance = trip_dist;
|
||||
route = std::move(curr_route);
|
||||
}
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
} // end namespace trip
|
||||
} // end namespace osrm
|
||||
#endif // TRIP_NEAREST_NEIGHBOUR_HPP
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TRIP_BRUTE_FORCE_HPP
|
||||
#define TRIP_BRUTE_FORCE_HPP
|
||||
|
||||
#include "../data_structures/search_engine.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
|
||||
#include <osrm/json_container.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace trip
|
||||
{
|
||||
|
||||
// todo: yet to be implemented
|
||||
void TabuSearchTrip(std::vector<unsigned> &location,
|
||||
const PhantomNodeArray &phantom_node_vector,
|
||||
const std::vector<EdgeWeight> &dist_table,
|
||||
InternalRouteResult &min_route,
|
||||
std::vector<int> &min_loc_permutation)
|
||||
{
|
||||
}
|
||||
|
||||
void TabuSearchTrip(const PhantomNodeArray &phantom_node_vector,
|
||||
const std::vector<EdgeWeight> &dist_table,
|
||||
InternalRouteResult &min_route,
|
||||
std::vector<int> &min_loc_permutation)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // TRIP_BRUTE_FORCE_HPP
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_COMPRESSOR_HPP_
|
||||
#define GEOMETRY_COMPRESSOR_HPP_
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CompressedEdgeContainer
|
||||
{
|
||||
public:
|
||||
using CompressedNode = std::pair<NodeID, EdgeWeight>;
|
||||
using EdgeBucket = std::vector<CompressedNode>;
|
||||
|
||||
CompressedEdgeContainer();
|
||||
void CompressEdge(const EdgeID surviving_edge_id,
|
||||
const EdgeID removed_edge_id,
|
||||
const NodeID via_node_id,
|
||||
const NodeID target_node,
|
||||
const EdgeWeight weight1,
|
||||
const EdgeWeight weight2);
|
||||
|
||||
bool HasEntryForID(const EdgeID edge_id) const;
|
||||
void PrintStatistics() const;
|
||||
void SerializeInternalVector(const std::string &path) const;
|
||||
unsigned GetPositionForID(const EdgeID edge_id) const;
|
||||
const EdgeBucket& GetBucketReference(const EdgeID edge_id) const;
|
||||
NodeID GetFirstEdgeTargetID(const EdgeID edge_id) const;
|
||||
NodeID GetLastEdgeSourceID(const EdgeID edge_id) const;
|
||||
|
||||
private:
|
||||
int free_list_maximum = 0;
|
||||
|
||||
void IncreaseFreeList();
|
||||
std::vector<EdgeBucket> m_compressed_geometries;
|
||||
std::vector<unsigned> m_free_list;
|
||||
std::unordered_map<EdgeID, unsigned> m_edge_id_to_list_index_map;
|
||||
};
|
||||
|
||||
#endif // GEOMETRY_COMPRESSOR_HPP_
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
// This class constructs the edge-expanded routing graph
|
||||
|
||||
#ifndef EDGE_BASED_GRAPH_FACTORY_HPP_
|
||||
#define EDGE_BASED_GRAPH_FACTORY_HPP_
|
||||
|
||||
#include "speed_profile.hpp"
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/compressed_edge_container.hpp"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/edge_based_node.hpp"
|
||||
#include "../data_structures/original_edge_data.hpp"
|
||||
#include "../data_structures/query_node.hpp"
|
||||
#include "../data_structures/turn_instructions.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
#include "../data_structures/restriction_map.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
class EdgeBasedGraphFactory
|
||||
{
|
||||
public:
|
||||
EdgeBasedGraphFactory() = delete;
|
||||
EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
|
||||
|
||||
explicit EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
std::shared_ptr<const RestrictionMap> restriction_map,
|
||||
const std::vector<QueryNode> &node_info_list,
|
||||
SpeedProfileProperties speed_profile);
|
||||
|
||||
#ifdef DEBUG_GEOMETRY
|
||||
void Run(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_penalty_filename,
|
||||
const bool generate_edge_lookup,
|
||||
const std::string &debug_turns_path);
|
||||
#else
|
||||
void Run(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_penalty_filename,
|
||||
const bool generate_edge_lookup);
|
||||
#endif
|
||||
|
||||
void GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &edges);
|
||||
|
||||
void GetEdgeBasedNodes(std::vector<EdgeBasedNode> &nodes);
|
||||
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
||||
|
||||
unsigned GetHighestEdgeID();
|
||||
|
||||
TurnInstruction AnalyzeTurn(const NodeID u, const NodeID v, const NodeID w, const double angle) const;
|
||||
|
||||
int GetTurnPenalty(double angle, lua_State *lua_state) const;
|
||||
|
||||
private:
|
||||
using EdgeData = NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
//! maps index from m_edge_based_node_list to ture/false if the node is an entry point to the graph
|
||||
std::vector<bool> m_edge_based_node_is_startpoint;
|
||||
//! list of edge based nodes (compressed segments)
|
||||
std::vector<EdgeBasedNode> m_edge_based_node_list;
|
||||
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
unsigned m_max_edge_id;
|
||||
|
||||
const std::vector<QueryNode>& m_node_info_list;
|
||||
std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
|
||||
std::shared_ptr<RestrictionMap const> m_restriction_map;
|
||||
|
||||
const std::unordered_set<NodeID>& m_barrier_nodes;
|
||||
const std::unordered_set<NodeID>& m_traffic_lights;
|
||||
const CompressedEdgeContainer& m_compressed_edge_container;
|
||||
|
||||
SpeedProfileProperties speed_profile;
|
||||
|
||||
void CompressGeometry();
|
||||
unsigned RenumberEdges();
|
||||
void GenerateEdgeExpandedNodes();
|
||||
#ifdef DEBUG_GEOMETRY
|
||||
void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_fixed_penalties_filename,
|
||||
const bool generate_edge_lookup,
|
||||
const std::string &debug_turns_path);
|
||||
#else
|
||||
void GenerateEdgeExpandedEdges(const std::string &original_edge_data_filename,
|
||||
lua_State *lua_state,
|
||||
const std::string &edge_segment_lookup_filename,
|
||||
const std::string &edge_fixed_penalties_filename,
|
||||
const bool generate_edge_lookup);
|
||||
#endif
|
||||
|
||||
void InsertEdgeBasedNode(const NodeID u, const NodeID v);
|
||||
|
||||
void FlushVectorToStream(std::ofstream &edge_data_file,
|
||||
std::vector<OriginalEdgeData> &original_edge_data_vector) const;
|
||||
|
||||
};
|
||||
|
||||
#endif /* EDGE_BASED_GRAPH_FACTORY_HPP_ */
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EDGE_BASED_NODE_HPP
|
||||
#define EDGE_BASED_NODE_HPP
|
||||
|
||||
#include "../data_structures/travel_mode.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
/// This is what StaticRTree serialized and stores on disk
|
||||
/// It is generated in EdgeBasedGraphFactory.
|
||||
struct EdgeBasedNode
|
||||
{
|
||||
EdgeBasedNode()
|
||||
: forward_edge_based_node_id(SPECIAL_NODEID), reverse_edge_based_node_id(SPECIAL_NODEID),
|
||||
u(SPECIAL_NODEID), v(SPECIAL_NODEID), name_id(0),
|
||||
forward_weight(INVALID_EDGE_WEIGHT >> 1), reverse_weight(INVALID_EDGE_WEIGHT >> 1),
|
||||
forward_offset(0), reverse_offset(0), packed_geometry_id(SPECIAL_EDGEID),
|
||||
component{INVALID_COMPONENTID, false}, fwd_segment_position(std::numeric_limits<unsigned short>::max()),
|
||||
forward_travel_mode(TRAVEL_MODE_INACCESSIBLE),
|
||||
backward_travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
}
|
||||
|
||||
explicit EdgeBasedNode(NodeID forward_edge_based_node_id,
|
||||
NodeID reverse_edge_based_node_id,
|
||||
NodeID u,
|
||||
NodeID v,
|
||||
unsigned name_id,
|
||||
int forward_weight,
|
||||
int reverse_weight,
|
||||
int forward_offset,
|
||||
int reverse_offset,
|
||||
unsigned packed_geometry_id,
|
||||
bool is_tiny_component,
|
||||
unsigned component_id,
|
||||
unsigned short fwd_segment_position,
|
||||
TravelMode forward_travel_mode,
|
||||
TravelMode backward_travel_mode)
|
||||
: forward_edge_based_node_id(forward_edge_based_node_id),
|
||||
reverse_edge_based_node_id(reverse_edge_based_node_id), u(u), v(v), name_id(name_id),
|
||||
forward_weight(forward_weight), reverse_weight(reverse_weight),
|
||||
forward_offset(forward_offset), reverse_offset(reverse_offset),
|
||||
packed_geometry_id(packed_geometry_id), component{component_id, is_tiny_component},
|
||||
fwd_segment_position(fwd_segment_position), forward_travel_mode(forward_travel_mode),
|
||||
backward_travel_mode(backward_travel_mode)
|
||||
{
|
||||
BOOST_ASSERT((forward_edge_based_node_id != SPECIAL_NODEID) ||
|
||||
(reverse_edge_based_node_id != SPECIAL_NODEID));
|
||||
}
|
||||
|
||||
static inline FixedPointCoordinate Centroid(const FixedPointCoordinate &a,
|
||||
const FixedPointCoordinate &b)
|
||||
{
|
||||
FixedPointCoordinate centroid;
|
||||
// The coordinates of the midpoint are given by:
|
||||
centroid.lat = (a.lat + b.lat) / 2;
|
||||
centroid.lon = (a.lon + b.lon) / 2;
|
||||
return centroid;
|
||||
}
|
||||
|
||||
bool IsCompressed() const { return packed_geometry_id != SPECIAL_EDGEID; }
|
||||
|
||||
NodeID forward_edge_based_node_id; // needed for edge-expanded graph
|
||||
NodeID reverse_edge_based_node_id; // needed for edge-expanded graph
|
||||
NodeID u; // indices into the coordinates array
|
||||
NodeID v; // indices into the coordinates array
|
||||
unsigned name_id; // id of the edge name
|
||||
int forward_weight; // weight of the edge
|
||||
int reverse_weight; // weight in the other direction (may be different)
|
||||
int forward_offset; // prefix sum of the weight up the edge TODO: short must suffice
|
||||
int reverse_offset; // prefix sum of the weight from the edge TODO: short must suffice
|
||||
unsigned packed_geometry_id; // if set, then the edge represents a packed geometry
|
||||
struct {
|
||||
unsigned id : 31;
|
||||
bool is_tiny : 1;
|
||||
} component;
|
||||
unsigned short fwd_segment_position; // segment id in a compressed geometry
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
};
|
||||
|
||||
#endif // EDGE_BASED_NODE_HPP
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTERNAL_MEMORY_NODE_HPP_
|
||||
#define EXTERNAL_MEMORY_NODE_HPP_
|
||||
|
||||
#include "query_node.hpp"
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct ExternalMemoryNode : QueryNode
|
||||
{
|
||||
ExternalMemoryNode(int lat, int lon, OSMNodeID id, bool barrier, bool traffic_light);
|
||||
|
||||
ExternalMemoryNode();
|
||||
|
||||
static ExternalMemoryNode min_value();
|
||||
|
||||
static ExternalMemoryNode max_value();
|
||||
|
||||
bool barrier;
|
||||
bool traffic_lights;
|
||||
};
|
||||
|
||||
struct ExternalMemoryNodeSTXXLCompare
|
||||
{
|
||||
using value_type = ExternalMemoryNode;
|
||||
bool operator()(const ExternalMemoryNode &left, const ExternalMemoryNode &right) const;
|
||||
value_type max_value();
|
||||
value_type min_value();
|
||||
};
|
||||
|
||||
#endif /* EXTERNAL_MEMORY_NODE_HPP_ */
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTION_CONTAINERS_HPP
|
||||
#define EXTRACTION_CONTAINERS_HPP
|
||||
|
||||
#include "internal_extractor_edge.hpp"
|
||||
#include "first_and_last_segment_of_way.hpp"
|
||||
#include "scripting_environment.hpp"
|
||||
#include "../data_structures/external_memory_node.hpp"
|
||||
#include "../data_structures/restriction.hpp"
|
||||
|
||||
#include <stxxl/vector>
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* Uses external memory containers from stxxl to store all the data that
|
||||
* is collected by the extractor callbacks.
|
||||
*
|
||||
* The data is the filtered, aggregated and finally written to disk.
|
||||
*/
|
||||
class ExtractionContainers
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
constexpr static unsigned stxxl_memory =
|
||||
((sizeof(std::size_t) == 4) ? std::numeric_limits<int>::max()
|
||||
: std::numeric_limits<unsigned>::max());
|
||||
#else
|
||||
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
|
||||
#endif
|
||||
void PrepareNodes();
|
||||
void PrepareRestrictions();
|
||||
void PrepareEdges(lua_State *segment_state);
|
||||
|
||||
void WriteNodes(std::ofstream& file_out_stream) const;
|
||||
void WriteRestrictions(const std::string& restrictions_file_name) const;
|
||||
void WriteEdges(std::ofstream& file_out_stream) const;
|
||||
void WriteNames(const std::string& names_file_name) const;
|
||||
public:
|
||||
using STXXLNodeIDVector = stxxl::vector<OSMNodeID>;
|
||||
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
|
||||
using STXXLEdgeVector = stxxl::vector<InternalExtractorEdge>;
|
||||
using STXXLRestrictionsVector = stxxl::vector<InputRestrictionContainer>;
|
||||
using STXXLWayIDStartEndVector = stxxl::vector<FirstAndLastSegmentOfWay>;
|
||||
|
||||
STXXLNodeIDVector used_node_id_list;
|
||||
STXXLNodeVector all_nodes_list;
|
||||
STXXLEdgeVector all_edges_list;
|
||||
stxxl::vector<char> name_char_data;
|
||||
stxxl::vector<unsigned> name_lengths;
|
||||
STXXLRestrictionsVector restrictions_list;
|
||||
STXXLWayIDStartEndVector way_start_end_id_list;
|
||||
std::unordered_map<OSMNodeID, NodeID> external_to_internal_node_id_map;
|
||||
unsigned max_internal_node_id;
|
||||
|
||||
ExtractionContainers();
|
||||
|
||||
~ExtractionContainers();
|
||||
|
||||
void PrepareData(const std::string &output_file_name,
|
||||
const std::string &restrictions_file_name,
|
||||
const std::string &names_file_name,
|
||||
lua_State *segment_state);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTION_CONTAINERS_HPP */
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTION_HELPER_FUNCTIONS_HPP
|
||||
#define EXTRACTION_HELPER_FUNCTIONS_HPP
|
||||
|
||||
#include "../util/cast.hpp"
|
||||
#include "../util/iso_8601_duration_parser.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string_regex.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
bool simple_duration_is_valid(const std::string &s)
|
||||
{
|
||||
boost::regex simple_format(
|
||||
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
|
||||
boost::regex_constants::icase | boost::regex_constants::perl);
|
||||
|
||||
const bool simple_matched = regex_match(s, simple_format);
|
||||
|
||||
if (simple_matched)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool iso_8601_duration_is_valid(const std::string &s)
|
||||
{
|
||||
iso_8601_grammar<std::string::const_iterator> iso_parser;
|
||||
const bool result = qi::parse(s.begin(), s.end(), iso_parser);
|
||||
|
||||
// check if the was an error with the request
|
||||
if (result && (0 != iso_parser.get_duration()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool durationIsValid(const std::string &s)
|
||||
{
|
||||
return simple_duration_is_valid(s) || iso_8601_duration_is_valid(s);
|
||||
}
|
||||
|
||||
unsigned parseDuration(const std::string &s)
|
||||
{
|
||||
if (simple_duration_is_valid(s))
|
||||
{
|
||||
unsigned hours = 0;
|
||||
unsigned minutes = 0;
|
||||
unsigned seconds = 0;
|
||||
boost::regex e(
|
||||
"((\\d|\\d\\d):(\\d|\\d\\d):(\\d|\\d\\d))|((\\d|\\d\\d):(\\d|\\d\\d))|(\\d|\\d\\d)",
|
||||
boost::regex_constants::icase | boost::regex_constants::perl);
|
||||
|
||||
std::vector<std::string> result;
|
||||
boost::algorithm::split_regex(result, s, boost::regex(":"));
|
||||
const bool matched = regex_match(s, e);
|
||||
if (matched)
|
||||
{
|
||||
if (1 == result.size())
|
||||
{
|
||||
minutes = std::stoul(result[0]);
|
||||
}
|
||||
if (2 == result.size())
|
||||
{
|
||||
minutes = std::stoul(result[1]);
|
||||
hours = std::stoul(result[0]);
|
||||
}
|
||||
if (3 == result.size())
|
||||
{
|
||||
seconds = std::stoul(result[2]);
|
||||
minutes = std::stoul(result[1]);
|
||||
hours = std::stoul(result[0]);
|
||||
}
|
||||
return (3600 * hours + 60 * minutes + seconds);
|
||||
}
|
||||
}
|
||||
else if (iso_8601_duration_is_valid(s))
|
||||
{
|
||||
iso_8601_grammar<std::string::const_iterator> iso_parser;
|
||||
qi::parse(s.begin(), s.end(), iso_parser);
|
||||
|
||||
return iso_parser.get_duration();
|
||||
}
|
||||
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
#endif // EXTRACTION_HELPER_FUNCTIONS_HPP
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTION_NODE_HPP
|
||||
#define EXTRACTION_NODE_HPP
|
||||
|
||||
struct ExtractionNode
|
||||
{
|
||||
ExtractionNode() : traffic_lights(false), barrier(false) {}
|
||||
void clear() { traffic_lights = barrier = false; }
|
||||
bool traffic_lights;
|
||||
bool barrier;
|
||||
};
|
||||
#endif // EXTRACTION_NODE_HPP
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTION_WAY_HPP
|
||||
#define EXTRACTION_WAY_HPP
|
||||
|
||||
#include "../data_structures/travel_mode.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* This struct is the direct result of the call to ```way_function```
|
||||
* in the lua based profile.
|
||||
*
|
||||
* It is split into multiple edge segments in the ExtractorCallback.
|
||||
*/
|
||||
struct ExtractionWay
|
||||
{
|
||||
ExtractionWay() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
forward_speed = -1;
|
||||
backward_speed = -1;
|
||||
duration = -1;
|
||||
roundabout = false;
|
||||
is_startpoint = true;
|
||||
is_access_restricted = false;
|
||||
name.clear();
|
||||
forward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
backward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
}
|
||||
|
||||
enum Directions
|
||||
{
|
||||
notSure = 0,
|
||||
oneway,
|
||||
bidirectional,
|
||||
opposite
|
||||
};
|
||||
|
||||
// These accessor methods exists to support the depreciated "way.direction" access
|
||||
// in LUA. Since the direction attribute was removed from ExtractionWay, the
|
||||
// accessors translate to/from the mode attributes.
|
||||
void set_direction(const Directions m)
|
||||
{
|
||||
if (Directions::oneway == m)
|
||||
{
|
||||
forward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
}
|
||||
else if (Directions::opposite == m)
|
||||
{
|
||||
forward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
|
||||
backward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
}
|
||||
else if (Directions::bidirectional == m)
|
||||
{
|
||||
forward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
backward_travel_mode = TRAVEL_MODE_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
Directions get_direction() const
|
||||
{
|
||||
if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode &&
|
||||
TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
|
||||
{
|
||||
return Directions::bidirectional;
|
||||
}
|
||||
else if (TRAVEL_MODE_INACCESSIBLE != forward_travel_mode)
|
||||
{
|
||||
return Directions::oneway;
|
||||
}
|
||||
else if (TRAVEL_MODE_INACCESSIBLE != backward_travel_mode)
|
||||
{
|
||||
return Directions::opposite;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Directions::notSure;
|
||||
}
|
||||
}
|
||||
|
||||
// These accessors exists because it's not possible to take the address of a bitfield,
|
||||
// and LUA therefore cannot read/write the mode attributes directly.
|
||||
void set_forward_mode(const TravelMode m) { forward_travel_mode = m; }
|
||||
TravelMode get_forward_mode() const { return forward_travel_mode; }
|
||||
void set_backward_mode(const TravelMode m) { backward_travel_mode = m; }
|
||||
TravelMode get_backward_mode() const { return backward_travel_mode; }
|
||||
|
||||
double forward_speed;
|
||||
double backward_speed;
|
||||
double duration;
|
||||
std::string name;
|
||||
bool roundabout;
|
||||
bool is_access_restricted;
|
||||
bool is_startpoint;
|
||||
TravelMode forward_travel_mode : 4;
|
||||
TravelMode backward_travel_mode : 4;
|
||||
};
|
||||
|
||||
#endif // EXTRACTION_WAY_HPP
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTOR_HPP
|
||||
#define EXTRACTOR_HPP
|
||||
|
||||
#include "extractor_options.hpp"
|
||||
#include "edge_based_graph_factory.hpp"
|
||||
#include "../algorithms/graph_compressor.hpp"
|
||||
|
||||
class extractor
|
||||
{
|
||||
public:
|
||||
extractor(ExtractorConfig extractor_config) : config(std::move(extractor_config)) {}
|
||||
int run();
|
||||
|
||||
private:
|
||||
ExtractorConfig config;
|
||||
void SetupScriptingEnvironment(lua_State *myLuaState, SpeedProfileProperties &speed_profile);
|
||||
std::pair<std::size_t, std::size_t>
|
||||
BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
|
||||
std::vector<EdgeBasedNode> &node_based_edge_list,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
|
||||
void WriteNodeMapping(const std::vector<QueryNode> &internal_to_external_node_map);
|
||||
void FindComponents(unsigned max_edge_id,
|
||||
const DeallocatingVector<EdgeBasedEdge> &edges,
|
||||
std::vector<EdgeBasedNode> &nodes) const;
|
||||
void BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list,
|
||||
std::vector<bool> node_is_startpoint,
|
||||
const std::vector<QueryNode> &internal_to_external_node_map);
|
||||
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
|
||||
std::shared_ptr<NodeBasedDynamicGraph>
|
||||
LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<QueryNode> &internal_to_external_node_map);
|
||||
|
||||
void WriteEdgeBasedGraph(std::string const &output_file_filename,
|
||||
size_t const max_edge_id,
|
||||
DeallocatingVector<EdgeBasedEdge> const &edge_based_edge_list);
|
||||
};
|
||||
#endif /* EXTRACTOR_HPP */
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTOR_CALLBACKS_HPP
|
||||
#define EXTRACTOR_CALLBACKS_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include <boost/optional/optional_fwd.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
struct ExternalMemoryNode;
|
||||
class ExtractionContainers;
|
||||
struct InputRestrictionContainer;
|
||||
struct ExtractionNode;
|
||||
struct ExtractionWay;
|
||||
namespace osmium
|
||||
{
|
||||
class Node;
|
||||
class Way;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is uses by the extractor with the results of the
|
||||
* osmium based parsing and the customization through the lua profile.
|
||||
*
|
||||
* It mediates between the multi-threaded extraction process and the external memory containers.
|
||||
* Thus the synchronization is handled inside of the extractor.
|
||||
*/
|
||||
class ExtractorCallbacks
|
||||
{
|
||||
private:
|
||||
// used to deduplicate street names: actually maps to name ids
|
||||
std::unordered_map<std::string, NodeID> string_map;
|
||||
ExtractionContainers &external_memory;
|
||||
|
||||
public:
|
||||
ExtractorCallbacks() = delete;
|
||||
ExtractorCallbacks(const ExtractorCallbacks &) = delete;
|
||||
explicit ExtractorCallbacks(ExtractionContainers &extraction_containers);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessNode(const osmium::Node ¤t_node, const ExtractionNode &result_node);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessRestriction(const boost::optional<InputRestrictionContainer> &restriction);
|
||||
|
||||
// warning: caller needs to take care of synchronization!
|
||||
void ProcessWay(const osmium::Way ¤t_way, const ExtractionWay &result_way);
|
||||
};
|
||||
|
||||
#endif /* EXTRACTOR_CALLBACKS_HPP */
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTRACTOR_OPTIONS_HPP
|
||||
#define EXTRACTOR_OPTIONS_HPP
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class return_code : unsigned
|
||||
{
|
||||
ok,
|
||||
fail,
|
||||
exit
|
||||
};
|
||||
|
||||
struct ExtractorConfig
|
||||
{
|
||||
ExtractorConfig() noexcept : requested_num_threads(0) {}
|
||||
boost::filesystem::path config_file_path;
|
||||
boost::filesystem::path input_path;
|
||||
boost::filesystem::path profile_path;
|
||||
|
||||
std::string output_file_name;
|
||||
std::string restriction_file_name;
|
||||
std::string names_file_name;
|
||||
std::string timestamp_file_name;
|
||||
std::string geometry_output_path;
|
||||
std::string edge_output_path;
|
||||
std::string edge_graph_output_path;
|
||||
std::string node_output_path;
|
||||
std::string rtree_nodes_output_path;
|
||||
std::string rtree_leafs_output_path;
|
||||
|
||||
unsigned requested_num_threads;
|
||||
unsigned small_component_size;
|
||||
|
||||
bool generate_edge_lookup;
|
||||
std::string edge_penalty_path;
|
||||
std::string edge_segment_lookup_path;
|
||||
#ifdef DEBUG_GEOMETRY
|
||||
std::string debug_turns_path;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ExtractorOptions
|
||||
{
|
||||
static return_code ParseArguments(int argc, char *argv[], ExtractorConfig &extractor_config);
|
||||
|
||||
static void GenerateOutputFilesNames(ExtractorConfig &extractor_config);
|
||||
};
|
||||
|
||||
#endif // EXTRACTOR_OPTIONS_HPP
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
|
||||
#define FIRST_AND_LAST_SEGMENT_OF_WAY_HPP
|
||||
|
||||
#include "../data_structures/external_memory_node.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
struct FirstAndLastSegmentOfWay
|
||||
{
|
||||
OSMWayID way_id;
|
||||
OSMNodeID first_segment_source_id;
|
||||
OSMNodeID first_segment_target_id;
|
||||
OSMNodeID last_segment_source_id;
|
||||
OSMNodeID last_segment_target_id;
|
||||
|
||||
FirstAndLastSegmentOfWay()
|
||||
: way_id(SPECIAL_OSM_WAYID),
|
||||
first_segment_source_id(SPECIAL_OSM_NODEID),
|
||||
first_segment_target_id(SPECIAL_OSM_NODEID),
|
||||
last_segment_source_id(SPECIAL_OSM_NODEID),
|
||||
last_segment_target_id(SPECIAL_OSM_NODEID)
|
||||
{
|
||||
}
|
||||
|
||||
FirstAndLastSegmentOfWay(OSMWayID w, OSMNodeID fs, OSMNodeID ft, OSMNodeID ls, OSMNodeID lt)
|
||||
: way_id(w), first_segment_source_id(fs), first_segment_target_id(ft),
|
||||
last_segment_source_id(ls), last_segment_target_id(lt)
|
||||
{
|
||||
}
|
||||
|
||||
static FirstAndLastSegmentOfWay min_value()
|
||||
{
|
||||
return {MIN_OSM_WAYID,
|
||||
MIN_OSM_NODEID,
|
||||
MIN_OSM_NODEID,
|
||||
MIN_OSM_NODEID,
|
||||
MIN_OSM_NODEID};
|
||||
}
|
||||
static FirstAndLastSegmentOfWay max_value()
|
||||
{
|
||||
return {MAX_OSM_WAYID,
|
||||
MAX_OSM_NODEID,
|
||||
MAX_OSM_NODEID,
|
||||
MAX_OSM_NODEID,
|
||||
MAX_OSM_NODEID};
|
||||
}
|
||||
};
|
||||
|
||||
struct FirstAndLastSegmentOfWayStxxlCompare
|
||||
{
|
||||
using value_type = FirstAndLastSegmentOfWay;
|
||||
bool operator()(const FirstAndLastSegmentOfWay &a, const FirstAndLastSegmentOfWay &b) const
|
||||
{
|
||||
return a.way_id < b.way_id;
|
||||
}
|
||||
value_type max_value() { return FirstAndLastSegmentOfWay::max_value(); }
|
||||
value_type min_value() { return FirstAndLastSegmentOfWay::min_value(); }
|
||||
};
|
||||
|
||||
#endif /* FIRST_AND_LAST_SEGMENT_OF_WAY_HPP */
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
#ifndef GEOMETRY_COMPRESSOR_HPP
|
||||
#define GEOMETRY_COMPRESSOR_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include "../extractor/speed_profile.hpp"
|
||||
#include "../data_structures/node_based_graph.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
class CompressedEdgeContainer;
|
||||
class RestrictionMap;
|
||||
|
||||
class GraphCompressor
|
||||
{
|
||||
using EdgeData = NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
public:
|
||||
GraphCompressor(SpeedProfileProperties speed_profile);
|
||||
|
||||
void Compress(const std::unordered_set<NodeID>& barrier_nodes,
|
||||
const std::unordered_set<NodeID>& traffic_lights,
|
||||
RestrictionMap& restriction_map,
|
||||
NodeBasedDynamicGraph& graph,
|
||||
CompressedEdgeContainer& geometry_compressor);
|
||||
private:
|
||||
|
||||
void PrintStatistics(unsigned original_number_of_nodes,
|
||||
unsigned original_number_of_edges,
|
||||
const NodeBasedDynamicGraph& graph) const;
|
||||
|
||||
SpeedProfileProperties speed_profile;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMPORT_EDGE_HPP
|
||||
#define IMPORT_EDGE_HPP
|
||||
|
||||
#include "../data_structures/travel_mode.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct NodeBasedEdge
|
||||
{
|
||||
bool operator<(const NodeBasedEdge &e) const;
|
||||
|
||||
NodeBasedEdge();
|
||||
explicit NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split);
|
||||
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID name_id;
|
||||
EdgeWeight weight;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
bool roundabout : 1;
|
||||
bool access_restricted : 1;
|
||||
bool startpoint : 1;
|
||||
bool is_split : 1;
|
||||
TravelMode travel_mode : 4;
|
||||
};
|
||||
|
||||
struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
{
|
||||
explicit NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
OSMNodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split)
|
||||
: NodeBasedEdge(SPECIAL_NODEID, SPECIAL_NODEID, name_id, weight, forward, backward, roundabout, access_restricted, startpoint, travel_mode, is_split),
|
||||
osm_source_id(source), osm_target_id(target) {}
|
||||
|
||||
OSMNodeID osm_source_id;
|
||||
OSMNodeID osm_target_id;
|
||||
};
|
||||
|
||||
struct EdgeBasedEdge
|
||||
{
|
||||
|
||||
public:
|
||||
bool operator<(const EdgeBasedEdge &e) const;
|
||||
|
||||
template <class EdgeT> explicit EdgeBasedEdge(const EdgeT &myEdge);
|
||||
|
||||
EdgeBasedEdge();
|
||||
|
||||
explicit EdgeBasedEdge(const NodeID source,
|
||||
const NodeID target,
|
||||
const NodeID edge_id,
|
||||
const EdgeWeight weight,
|
||||
const bool forward,
|
||||
const bool backward);
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
NodeID edge_id;
|
||||
EdgeWeight weight : 30;
|
||||
bool forward : 1;
|
||||
bool backward : 1;
|
||||
};
|
||||
|
||||
#endif /* IMPORT_EDGE_HPP */
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INTERNAL_EXTRACTOR_EDGE_HPP
|
||||
#define INTERNAL_EXTRACTOR_EDGE_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/travel_mode.hpp"
|
||||
#include "../data_structures/import_edge.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
#include <utility>
|
||||
|
||||
struct InternalExtractorEdge
|
||||
{
|
||||
// specify the type of the weight data
|
||||
enum class WeightType : char {
|
||||
INVALID,
|
||||
SPEED,
|
||||
EDGE_DURATION,
|
||||
WAY_DURATION,
|
||||
};
|
||||
|
||||
struct WeightData
|
||||
{
|
||||
|
||||
WeightData() : duration(0.0), type(WeightType::INVALID)
|
||||
{
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
double duration;
|
||||
double speed;
|
||||
};
|
||||
WeightType type;
|
||||
};
|
||||
|
||||
explicit InternalExtractorEdge()
|
||||
: result(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, 0, false, false, false, false, true,
|
||||
TRAVEL_MODE_INACCESSIBLE, false)
|
||||
{
|
||||
}
|
||||
|
||||
explicit InternalExtractorEdge(OSMNodeID source,
|
||||
OSMNodeID target,
|
||||
NodeID name_id,
|
||||
WeightData weight_data,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool access_restricted,
|
||||
bool startpoint,
|
||||
TravelMode travel_mode,
|
||||
bool is_split)
|
||||
: result(OSMNodeID(source),
|
||||
OSMNodeID(target),
|
||||
name_id,
|
||||
0,
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
access_restricted,
|
||||
startpoint,
|
||||
travel_mode,
|
||||
is_split),
|
||||
weight_data(std::move(weight_data))
|
||||
{
|
||||
}
|
||||
|
||||
// data that will be written to disk
|
||||
NodeBasedEdgeWithOSM result;
|
||||
// intermediate edge weight
|
||||
WeightData weight_data;
|
||||
// coordinate of the source node
|
||||
FixedPointCoordinate source_coordinate;
|
||||
|
||||
|
||||
// necessary static util functions for stxxl's sorting
|
||||
static InternalExtractorEdge min_osm_value()
|
||||
{
|
||||
return InternalExtractorEdge(MIN_OSM_NODEID, MIN_OSM_NODEID, 0, WeightData(), false, false, false,
|
||||
false, true, TRAVEL_MODE_INACCESSIBLE, false);
|
||||
}
|
||||
static InternalExtractorEdge max_osm_value()
|
||||
{
|
||||
return InternalExtractorEdge(MAX_OSM_NODEID, MAX_OSM_NODEID, 0, WeightData(), false,
|
||||
false, false, false, true, TRAVEL_MODE_INACCESSIBLE, false);
|
||||
}
|
||||
|
||||
static InternalExtractorEdge min_internal_value()
|
||||
{
|
||||
auto v = min_osm_value();
|
||||
v.result.source = 0;
|
||||
v.result.target = 0;
|
||||
return v;
|
||||
}
|
||||
static InternalExtractorEdge max_internal_value()
|
||||
{
|
||||
auto v = max_osm_value();
|
||||
v.result.source = std::numeric_limits<NodeID>::max();
|
||||
v.result.target = std::numeric_limits<NodeID>::max();
|
||||
return v;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct CmpEdgeByInternalStartThenInternalTargetID
|
||||
{
|
||||
using value_type = InternalExtractorEdge;
|
||||
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
|
||||
{
|
||||
return (lhs.result.source < rhs.result.source) ||
|
||||
((lhs.result.source == rhs.result.source) &&
|
||||
(lhs.result.target < rhs.result.target));
|
||||
}
|
||||
|
||||
value_type max_value() { return InternalExtractorEdge::max_internal_value(); }
|
||||
value_type min_value() { return InternalExtractorEdge::min_internal_value(); }
|
||||
};
|
||||
|
||||
struct CmpEdgeByOSMStartID
|
||||
{
|
||||
using value_type = InternalExtractorEdge;
|
||||
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
|
||||
{
|
||||
return lhs.result.osm_source_id < rhs.result.osm_source_id;
|
||||
}
|
||||
|
||||
value_type max_value() { return InternalExtractorEdge::max_osm_value(); }
|
||||
value_type min_value() { return InternalExtractorEdge::min_osm_value(); }
|
||||
};
|
||||
|
||||
struct CmpEdgeByOSMTargetID
|
||||
{
|
||||
using value_type = InternalExtractorEdge;
|
||||
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
|
||||
{
|
||||
return lhs.result.osm_target_id < rhs.result.osm_target_id;
|
||||
}
|
||||
|
||||
value_type max_value() { return InternalExtractorEdge::max_osm_value(); }
|
||||
value_type min_value() { return InternalExtractorEdge::min_osm_value(); }
|
||||
};
|
||||
|
||||
#endif // INTERNAL_EXTRACTOR_EDGE_HPP
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NODE_ID_HPP
|
||||
#define NODE_ID_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct Cmp
|
||||
{
|
||||
using value_type = OSMNodeID;
|
||||
bool operator()(const value_type left, const value_type right) const { return left < right; }
|
||||
value_type max_value() { return MAX_OSM_NODEID; }
|
||||
value_type min_value() { return MIN_OSM_NODEID; }
|
||||
};
|
||||
|
||||
#endif // NODE_ID_HPP
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ORIGINAL_EDGE_DATA_HPP
|
||||
#define ORIGINAL_EDGE_DATA_HPP
|
||||
|
||||
#include "travel_mode.hpp"
|
||||
#include "turn_instructions.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct OriginalEdgeData
|
||||
{
|
||||
explicit OriginalEdgeData(NodeID via_node,
|
||||
unsigned name_id,
|
||||
TurnInstruction turn_instruction,
|
||||
bool compressed_geometry,
|
||||
TravelMode travel_mode)
|
||||
: via_node(via_node), name_id(name_id), turn_instruction(turn_instruction),
|
||||
compressed_geometry(compressed_geometry), travel_mode(travel_mode)
|
||||
{
|
||||
}
|
||||
|
||||
OriginalEdgeData()
|
||||
: via_node(std::numeric_limits<unsigned>::max()),
|
||||
name_id(std::numeric_limits<unsigned>::max()), turn_instruction(TurnInstruction::NoTurn),
|
||||
compressed_geometry(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
|
||||
{
|
||||
}
|
||||
|
||||
NodeID via_node;
|
||||
unsigned name_id;
|
||||
TurnInstruction turn_instruction;
|
||||
bool compressed_geometry;
|
||||
TravelMode travel_mode;
|
||||
};
|
||||
|
||||
#endif // ORIGINAL_EDGE_DATA_HPP
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef QUERY_NODE_HPP
|
||||
#define QUERY_NODE_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct QueryNode
|
||||
{
|
||||
using key_type = OSMNodeID; // type of NodeID
|
||||
using value_type = int; // type of lat,lons
|
||||
|
||||
explicit QueryNode(int lat, int lon, OSMNodeID node_id) : lat(lat), lon(lon), node_id(node_id) {}
|
||||
QueryNode()
|
||||
: lat(std::numeric_limits<int>::max()), lon(std::numeric_limits<int>::max()),
|
||||
node_id(SPECIAL_OSM_NODEID)
|
||||
{
|
||||
}
|
||||
|
||||
int lat;
|
||||
int lon;
|
||||
OSMNodeID node_id;
|
||||
|
||||
static QueryNode min_value()
|
||||
{
|
||||
return QueryNode(static_cast<int>(-90 * COORDINATE_PRECISION),
|
||||
static_cast<int>(-180 * COORDINATE_PRECISION),
|
||||
MIN_OSM_NODEID);
|
||||
}
|
||||
|
||||
static QueryNode max_value()
|
||||
{
|
||||
return QueryNode(static_cast<int>(90 * COORDINATE_PRECISION),
|
||||
static_cast<int>(180 * COORDINATE_PRECISION),
|
||||
MAX_OSM_NODEID);
|
||||
}
|
||||
|
||||
value_type operator[](const std::size_t n) const
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1:
|
||||
return lat;
|
||||
case 0:
|
||||
return lon;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT_MSG(false, "should not happen");
|
||||
return std::numeric_limits<int>::lowest();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // QUERY_NODE_HPP
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RASTER_SOURCE_HPP
|
||||
#define RASTER_SOURCE_HPP
|
||||
|
||||
#include "../util/osrm_exception.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/spirit/include/qi_int.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <iterator>
|
||||
|
||||
/**
|
||||
\brief Small wrapper around raster source queries to optionally provide results
|
||||
gracefully, depending on source bounds
|
||||
*/
|
||||
struct RasterDatum
|
||||
{
|
||||
static std::int32_t get_invalid() { return std::numeric_limits<std::int32_t>::max(); }
|
||||
|
||||
std::int32_t datum = get_invalid();
|
||||
|
||||
RasterDatum() = default;
|
||||
|
||||
RasterDatum(std::int32_t _datum) : datum(_datum) {}
|
||||
};
|
||||
|
||||
class RasterGrid
|
||||
{
|
||||
public:
|
||||
RasterGrid(const boost::filesystem::path &filepath, std::size_t _xdim, std::size_t _ydim)
|
||||
{
|
||||
xdim = _xdim;
|
||||
ydim = _ydim;
|
||||
_data.reserve(ydim * xdim);
|
||||
|
||||
boost::filesystem::ifstream stream(filepath);
|
||||
if (!stream)
|
||||
{
|
||||
throw osrm::exception("Unable to open raster file.");
|
||||
}
|
||||
|
||||
stream.seekg(0, std::ios_base::end);
|
||||
std::string buffer;
|
||||
buffer.resize(static_cast<std::size_t>(stream.tellg()));
|
||||
|
||||
stream.seekg(0, std::ios_base::beg);
|
||||
|
||||
BOOST_ASSERT(buffer.size() > 1);
|
||||
stream.read(&buffer[0], static_cast<std::streamsize>(buffer.size()));
|
||||
|
||||
boost::algorithm::trim(buffer);
|
||||
|
||||
auto itr = buffer.begin();
|
||||
auto end = buffer.end();
|
||||
|
||||
bool r = false;
|
||||
try
|
||||
{
|
||||
r = boost::spirit::qi::parse(
|
||||
itr, end, +boost::spirit::qi::int_ % +boost::spirit::qi::space, _data);
|
||||
}
|
||||
catch (std::exception const &ex)
|
||||
{
|
||||
throw osrm::exception(
|
||||
std::string("Failed to read from raster source with exception: ") + ex.what());
|
||||
}
|
||||
|
||||
if (!r || itr != end)
|
||||
{
|
||||
throw osrm::exception("Failed to parse raster source correctly.");
|
||||
}
|
||||
}
|
||||
|
||||
RasterGrid(const RasterGrid &) = default;
|
||||
RasterGrid &operator=(const RasterGrid &) = default;
|
||||
|
||||
RasterGrid(RasterGrid &&) = default;
|
||||
RasterGrid &operator=(RasterGrid &&) = default;
|
||||
|
||||
std::int32_t operator()(std::size_t x, std::size_t y) { return _data[y * xdim + x]; }
|
||||
std::int32_t operator()(std::size_t x, std::size_t y) const { return _data[(y)*xdim + (x)]; }
|
||||
|
||||
private:
|
||||
std::vector<std::int32_t> _data;
|
||||
std::size_t xdim, ydim;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Stores raster source data in memory and provides lookup functions.
|
||||
*/
|
||||
class RasterSource
|
||||
{
|
||||
private:
|
||||
const float xstep;
|
||||
const float ystep;
|
||||
|
||||
float calcSize(int min, int max, std::size_t count) const;
|
||||
|
||||
public:
|
||||
RasterGrid raster_data;
|
||||
|
||||
const std::size_t width;
|
||||
const std::size_t height;
|
||||
const int xmin;
|
||||
const int xmax;
|
||||
const int ymin;
|
||||
const int ymax;
|
||||
|
||||
RasterDatum getRasterData(const int lon, const int lat) const;
|
||||
|
||||
RasterDatum getRasterInterpolate(const int lon, const int lat) const;
|
||||
|
||||
RasterSource(RasterGrid _raster_data,
|
||||
std::size_t width,
|
||||
std::size_t height,
|
||||
int _xmin,
|
||||
int _xmax,
|
||||
int _ymin,
|
||||
int _ymax);
|
||||
};
|
||||
|
||||
class SourceContainer
|
||||
{
|
||||
public:
|
||||
SourceContainer() = default;
|
||||
|
||||
int loadRasterSource(const std::string &path_string,
|
||||
double xmin,
|
||||
double xmax,
|
||||
double ymin,
|
||||
double ymax,
|
||||
std::size_t nrows,
|
||||
std::size_t ncols);
|
||||
|
||||
RasterDatum getRasterDataFromSource(unsigned int source_id, int lon, int lat);
|
||||
|
||||
RasterDatum getRasterInterpolateFromSource(unsigned int source_id, int lon, int lat);
|
||||
|
||||
private:
|
||||
std::vector<RasterSource> LoadedSources;
|
||||
std::unordered_map<std::string, int> LoadedSourcePaths;
|
||||
};
|
||||
|
||||
#endif /* RASTER_SOURCE_HPP */
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RESTRICTION_HPP
|
||||
#define RESTRICTION_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
struct TurnRestriction
|
||||
{
|
||||
union WayOrNode
|
||||
{
|
||||
OSMNodeID_weak node;
|
||||
OSMEdgeID_weak way;
|
||||
};
|
||||
WayOrNode via;
|
||||
WayOrNode from;
|
||||
WayOrNode to;
|
||||
|
||||
struct Bits
|
||||
{ // mostly unused
|
||||
Bits()
|
||||
: is_only(false), uses_via_way(false), unused2(false), unused3(false), unused4(false),
|
||||
unused5(false), unused6(false), unused7(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_only : 1;
|
||||
bool uses_via_way : 1;
|
||||
bool unused2 : 1;
|
||||
bool unused3 : 1;
|
||||
bool unused4 : 1;
|
||||
bool unused5 : 1;
|
||||
bool unused6 : 1;
|
||||
bool unused7 : 1;
|
||||
} flags;
|
||||
|
||||
explicit TurnRestriction(NodeID node)
|
||||
{
|
||||
via.node = node;
|
||||
from.node = SPECIAL_NODEID;
|
||||
to.node = SPECIAL_NODEID;
|
||||
}
|
||||
|
||||
explicit TurnRestriction(const bool is_only = false)
|
||||
{
|
||||
via.node = SPECIAL_NODEID;
|
||||
from.node = SPECIAL_NODEID;
|
||||
to.node = SPECIAL_NODEID;
|
||||
flags.is_only = is_only;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is just a wrapper around TurnRestriction used in the extractor.
|
||||
*
|
||||
* Could be merged with TurnRestriction. For now the type-destiction makes sense
|
||||
* as the format in which the restriction is presented in the extractor and in the
|
||||
* preprocessing is different. (see restriction_parser.cpp)
|
||||
*/
|
||||
struct InputRestrictionContainer
|
||||
{
|
||||
TurnRestriction restriction;
|
||||
|
||||
InputRestrictionContainer(EdgeID fromWay, EdgeID toWay, EdgeID vw)
|
||||
{
|
||||
restriction.from.way = fromWay;
|
||||
restriction.to.way = toWay;
|
||||
restriction.via.way = vw;
|
||||
}
|
||||
explicit InputRestrictionContainer(bool is_only = false)
|
||||
{
|
||||
restriction.from.way = SPECIAL_EDGEID;
|
||||
restriction.to.way = SPECIAL_EDGEID;
|
||||
restriction.via.node = SPECIAL_NODEID;
|
||||
restriction.flags.is_only = is_only;
|
||||
}
|
||||
|
||||
static InputRestrictionContainer min_value() { return InputRestrictionContainer(0, 0, 0); }
|
||||
static InputRestrictionContainer max_value()
|
||||
{
|
||||
return InputRestrictionContainer(SPECIAL_EDGEID, SPECIAL_EDGEID, SPECIAL_EDGEID);
|
||||
}
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByFrom
|
||||
{
|
||||
using value_type = InputRestrictionContainer;
|
||||
bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
|
||||
{
|
||||
return a.restriction.from.way < b.restriction.from.way;
|
||||
}
|
||||
value_type max_value() const { return InputRestrictionContainer::max_value(); }
|
||||
value_type min_value() const { return InputRestrictionContainer::min_value(); }
|
||||
};
|
||||
|
||||
struct CmpRestrictionContainerByTo
|
||||
{
|
||||
using value_type = InputRestrictionContainer;
|
||||
bool operator()(const InputRestrictionContainer &a, const InputRestrictionContainer &b) const
|
||||
{
|
||||
return a.restriction.to.way < b.restriction.to.way;
|
||||
}
|
||||
value_type max_value() const { return InputRestrictionContainer::max_value(); }
|
||||
value_type min_value() const { return InputRestrictionContainer::min_value(); }
|
||||
};
|
||||
|
||||
#endif // RESTRICTION_HPP
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RESTRICTION_MAP_HPP
|
||||
#define RESTRICTION_MAP_HPP
|
||||
|
||||
#include "restriction.hpp"
|
||||
#include "../util/std_hash.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
struct RestrictionSource
|
||||
{
|
||||
NodeID start_node;
|
||||
NodeID via_node;
|
||||
|
||||
RestrictionSource(NodeID start, NodeID via) : start_node(start), via_node(via) {}
|
||||
|
||||
friend inline bool operator==(const RestrictionSource &lhs, const RestrictionSource &rhs)
|
||||
{
|
||||
return (lhs.start_node == rhs.start_node && lhs.via_node == rhs.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
struct RestrictionTarget
|
||||
{
|
||||
NodeID target_node;
|
||||
bool is_only;
|
||||
|
||||
explicit RestrictionTarget(NodeID target, bool only) : target_node(target), is_only(only) {}
|
||||
|
||||
friend inline bool operator==(const RestrictionTarget &lhs, const RestrictionTarget &rhs)
|
||||
{
|
||||
return (lhs.target_node == rhs.target_node && lhs.is_only == rhs.is_only);
|
||||
}
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<RestrictionSource>
|
||||
{
|
||||
size_t operator()(const RestrictionSource &r_source) const
|
||||
{
|
||||
return hash_val(r_source.start_node, r_source.via_node);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct hash<RestrictionTarget>
|
||||
{
|
||||
size_t operator()(const RestrictionTarget &r_target) const
|
||||
{
|
||||
return hash_val(r_target.target_node, r_target.is_only);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Efficent look up if an edge is the start + via node of a TurnRestriction
|
||||
EdgeBasedEdgeFactory decides by it if edges are inserted or geometry is compressed
|
||||
*/
|
||||
class RestrictionMap
|
||||
{
|
||||
public:
|
||||
RestrictionMap() : m_count(0) {};
|
||||
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
|
||||
|
||||
// Replace end v with w in each turn restriction containing u as via node
|
||||
template <class GraphT>
|
||||
void FixupArrivingTurnRestriction(const NodeID node_u,
|
||||
const NodeID node_v,
|
||||
const NodeID node_w,
|
||||
const GraphT &graph)
|
||||
{
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_w != SPECIAL_NODEID);
|
||||
|
||||
if (!IsViaNode(node_u))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// find all potential start edges. It is more efficent to get a (small) list
|
||||
// of potential start edges than iterating over all buckets
|
||||
std::vector<NodeID> predecessors;
|
||||
for (const EdgeID current_edge_id : graph.GetAdjacentEdgeRange(node_u))
|
||||
{
|
||||
const NodeID target = graph.GetTarget(current_edge_id);
|
||||
if (node_v != target)
|
||||
{
|
||||
predecessors.push_back(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const NodeID node_x : predecessors)
|
||||
{
|
||||
const auto restriction_iterator = m_restriction_map.find({node_x, node_u});
|
||||
if (restriction_iterator == m_restriction_map.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const unsigned index = restriction_iterator->second;
|
||||
auto &bucket = m_restriction_bucket_list.at(index);
|
||||
|
||||
for (RestrictionTarget &restriction_target : bucket)
|
||||
{
|
||||
if (node_v == restriction_target.target_node)
|
||||
{
|
||||
restriction_target.target_node = node_w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsViaNode(const NodeID node) const;
|
||||
|
||||
// Replaces start edge (v, w) with (u, w). Only start node changes.
|
||||
void
|
||||
FixupStartingTurnRestriction(const NodeID node_u, const NodeID node_v, const NodeID node_w);
|
||||
|
||||
// Check if edge (u, v) is the start of any turn restriction.
|
||||
// If so returns id of first target node.
|
||||
NodeID CheckForEmanatingIsOnlyTurn(const NodeID node_u, const NodeID node_v) const;
|
||||
// Checks if turn <u,v,w> is actually a turn restriction.
|
||||
bool
|
||||
CheckIfTurnIsRestricted(const NodeID node_u, const NodeID node_v, const NodeID node_w) const;
|
||||
|
||||
std::size_t size() const { return m_count; }
|
||||
|
||||
private:
|
||||
// check of node is the start of any restriction
|
||||
bool IsSourceNode(const NodeID node) const;
|
||||
|
||||
using EmanatingRestrictionsVector = std::vector<RestrictionTarget>;
|
||||
|
||||
std::size_t m_count;
|
||||
//! index -> list of (target, isOnly)
|
||||
std::vector<EmanatingRestrictionsVector> m_restriction_bucket_list;
|
||||
//! maps (start, via) -> bucket index
|
||||
std::unordered_map<RestrictionSource, unsigned> m_restriction_map;
|
||||
std::unordered_set<NodeID> m_restriction_start_nodes;
|
||||
std::unordered_set<NodeID> m_no_turn_via_node_set;
|
||||
};
|
||||
|
||||
#endif // RESTRICTION_MAP_HPP
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RESTRICTION_PARSER_HPP
|
||||
#define RESTRICTION_PARSER_HPP
|
||||
|
||||
#include "../data_structures/restriction.hpp"
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
namespace osmium
|
||||
{
|
||||
class Relation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the relations that represents turn restrictions.
|
||||
*
|
||||
* Currently only restrictions where the via objects is a node are supported.
|
||||
* from via to
|
||||
* ------->(x)-------->
|
||||
*
|
||||
* While this class does not directly invoke any lua code _per relation_ it does
|
||||
* load configuration values from the profile, that are saved in variables.
|
||||
* Namely ```use_turn_restrictions``` and ```get_exceptions```.
|
||||
*
|
||||
* The restriction is represented by the osm id of the from way, the osm id of the
|
||||
* to way and the osm id of the via node. This representation must be post-processed
|
||||
* in the extractor to work with the edge-based data-model of OSRM:
|
||||
* Since the from and to way share the via-node a turn will have the following form:
|
||||
* ...----(a)-----(via)------(b)----...
|
||||
* So it can be represented by the tripe (a, via, b).
|
||||
*/
|
||||
class RestrictionParser
|
||||
{
|
||||
public:
|
||||
RestrictionParser(lua_State *lua_state);
|
||||
boost::optional<InputRestrictionContainer> TryParse(const osmium::Relation &relation) const;
|
||||
|
||||
private:
|
||||
void ReadUseRestrictionsSetting(lua_State *lua_state);
|
||||
void ReadRestrictionExceptions(lua_State *lua_state);
|
||||
bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
|
||||
|
||||
std::vector<std::string> restriction_exceptions;
|
||||
bool use_turn_restrictions;
|
||||
};
|
||||
|
||||
#endif /* RESTRICTION_PARSER_HPP */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTING_ENVIRONMENT_HPP
|
||||
#define SCRIPTING_ENVIRONMENT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
/**
|
||||
* Creates a lua context and binds osmium way, node and relation objects and
|
||||
* ExtractionWay and ExtractionNode to lua objects.
|
||||
*
|
||||
* Each thread has its own lua state which is implemented with thread specific
|
||||
* storage from TBB.
|
||||
*/
|
||||
class ScriptingEnvironment
|
||||
{
|
||||
public:
|
||||
ScriptingEnvironment() = delete;
|
||||
explicit ScriptingEnvironment(const std::string &file_name);
|
||||
|
||||
lua_State *get_lua_state();
|
||||
|
||||
private:
|
||||
void init_lua_state(lua_State *lua_state);
|
||||
std::mutex init_mutex;
|
||||
std::string file_name;
|
||||
tbb::enumerable_thread_specific<std::shared_ptr<lua_State>> script_contexts;
|
||||
};
|
||||
|
||||
#endif /* SCRIPTING_ENVIRONMENT_HPP */
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef SPEED_PROFILE_PROPERTIES_HPP
|
||||
#define SPEED_PROFILE_PROPERTIES_HPP
|
||||
|
||||
struct SpeedProfileProperties
|
||||
{
|
||||
SpeedProfileProperties()
|
||||
: traffic_signal_penalty(0), u_turn_penalty(0), has_turn_penalty_function(false)
|
||||
{
|
||||
}
|
||||
|
||||
int traffic_signal_penalty;
|
||||
int u_turn_penalty;
|
||||
bool has_turn_penalty_function;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TARJAN_SCC_HPP
|
||||
#define TARJAN_SCC_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../data_structures/deallocating_vector.hpp"
|
||||
#include "../data_structures/import_edge.hpp"
|
||||
#include "../data_structures/query_node.hpp"
|
||||
#include "../data_structures/percent.hpp"
|
||||
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
#include "../util/std_hash.hpp"
|
||||
#include "../util/timing_util.hpp"
|
||||
|
||||
#include <osrm/coordinate.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
template <typename GraphT> class TarjanSCC
|
||||
{
|
||||
struct TarjanStackFrame
|
||||
{
|
||||
explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
|
||||
NodeID v;
|
||||
NodeID parent;
|
||||
};
|
||||
|
||||
struct TarjanNode
|
||||
{
|
||||
TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
|
||||
unsigned index;
|
||||
unsigned low_link;
|
||||
bool on_stack;
|
||||
};
|
||||
|
||||
std::vector<unsigned> components_index;
|
||||
std::vector<NodeID> component_size_vector;
|
||||
std::shared_ptr<const GraphT> m_graph;
|
||||
std::size_t size_one_counter;
|
||||
|
||||
public:
|
||||
TarjanSCC(std::shared_ptr<const GraphT> graph)
|
||||
: components_index(graph->GetNumberOfNodes(), SPECIAL_NODEID), m_graph(graph),
|
||||
size_one_counter(0)
|
||||
{
|
||||
BOOST_ASSERT(m_graph->GetNumberOfNodes() > 0);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
TIMER_START(SCC_RUN);
|
||||
const NodeID max_node_id = m_graph->GetNumberOfNodes();
|
||||
|
||||
// The following is a hack to distinguish between stuff that happens
|
||||
// before the recursive call and stuff that happens after
|
||||
std::stack<TarjanStackFrame> recursion_stack;
|
||||
// true = stuff before, false = stuff after call
|
||||
std::stack<NodeID> tarjan_stack;
|
||||
std::vector<TarjanNode> tarjan_node_list(max_node_id);
|
||||
unsigned component_index = 0, size_of_current_component = 0;
|
||||
unsigned index = 0;
|
||||
std::vector<bool> processing_node_before_recursion(max_node_id, true);
|
||||
for (const NodeID node : osrm::irange(0u, max_node_id))
|
||||
{
|
||||
if (SPECIAL_NODEID == components_index[node])
|
||||
{
|
||||
recursion_stack.emplace(TarjanStackFrame(node, node));
|
||||
}
|
||||
|
||||
while (!recursion_stack.empty())
|
||||
{
|
||||
TarjanStackFrame currentFrame = recursion_stack.top();
|
||||
const NodeID u = currentFrame.parent;
|
||||
const NodeID v = currentFrame.v;
|
||||
recursion_stack.pop();
|
||||
|
||||
const bool before_recursion = processing_node_before_recursion[v];
|
||||
|
||||
if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (before_recursion)
|
||||
{
|
||||
// Mark frame to handle tail of recursion
|
||||
recursion_stack.emplace(currentFrame);
|
||||
processing_node_before_recursion[v] = false;
|
||||
|
||||
// Mark essential information for SCC
|
||||
tarjan_node_list[v].index = index;
|
||||
tarjan_node_list[v].low_link = index;
|
||||
tarjan_stack.push(v);
|
||||
tarjan_node_list[v].on_stack = true;
|
||||
++index;
|
||||
|
||||
for (const auto current_edge : m_graph->GetAdjacentEdgeRange(v))
|
||||
{
|
||||
const auto vprime = m_graph->GetTarget(current_edge);
|
||||
|
||||
if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
|
||||
{
|
||||
recursion_stack.emplace(TarjanStackFrame(vprime, v));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tarjan_node_list[vprime].on_stack &&
|
||||
tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
|
||||
{
|
||||
tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processing_node_before_recursion[v] = true;
|
||||
tarjan_node_list[u].low_link =
|
||||
std::min(tarjan_node_list[u].low_link, tarjan_node_list[v].low_link);
|
||||
// after recursion, lets do cycle checking
|
||||
// Check if we found a cycle. This is the bottom part of the recursion
|
||||
if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
|
||||
{
|
||||
NodeID vprime;
|
||||
do
|
||||
{
|
||||
vprime = tarjan_stack.top();
|
||||
tarjan_stack.pop();
|
||||
tarjan_node_list[vprime].on_stack = false;
|
||||
components_index[vprime] = component_index;
|
||||
++size_of_current_component;
|
||||
} while (v != vprime);
|
||||
|
||||
component_size_vector.emplace_back(size_of_current_component);
|
||||
|
||||
if (size_of_current_component > 1000)
|
||||
{
|
||||
SimpleLogger().Write() << "large component [" << component_index
|
||||
<< "]=" << size_of_current_component;
|
||||
}
|
||||
|
||||
++component_index;
|
||||
size_of_current_component = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_STOP(SCC_RUN);
|
||||
SimpleLogger().Write() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
|
||||
|
||||
size_one_counter = std::count_if(component_size_vector.begin(), component_size_vector.end(),
|
||||
[](unsigned value)
|
||||
{
|
||||
return 1 == value;
|
||||
});
|
||||
}
|
||||
|
||||
std::size_t get_number_of_components() const { return component_size_vector.size(); }
|
||||
|
||||
std::size_t get_size_one_count() const { return size_one_counter; }
|
||||
|
||||
unsigned get_component_size(const unsigned component_id) const
|
||||
{
|
||||
return component_size_vector[component_id];
|
||||
}
|
||||
|
||||
unsigned get_component_id(const NodeID node) const { return components_index[node]; }
|
||||
};
|
||||
|
||||
#endif /* TARJAN_SCC_HPP */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TRAVEL_MODE_HPP
|
||||
#define TRAVEL_MODE_HPP
|
||||
|
||||
namespace
|
||||
{
|
||||
using TravelMode = unsigned char;
|
||||
static const TravelMode TRAVEL_MODE_INACCESSIBLE = 0;
|
||||
static const TravelMode TRAVEL_MODE_DEFAULT = 1;
|
||||
}
|
||||
#endif /* TRAVEL_MODE_HPP */
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TURN_INSTRUCTIONS_HPP
|
||||
#define TURN_INSTRUCTIONS_HPP
|
||||
|
||||
enum class TurnInstruction : unsigned char
|
||||
{
|
||||
NoTurn = 0,
|
||||
GoStraight,
|
||||
TurnSlightRight,
|
||||
TurnRight,
|
||||
TurnSharpRight,
|
||||
UTurn,
|
||||
TurnSharpLeft,
|
||||
TurnLeft,
|
||||
TurnSlightLeft,
|
||||
ReachViaLocation,
|
||||
HeadOn,
|
||||
EnterRoundAbout,
|
||||
LeaveRoundAbout,
|
||||
StayOnRoundAbout,
|
||||
StartAtEndOfStreet,
|
||||
ReachedYourDestination,
|
||||
EnterAgainstAllowedDirection,
|
||||
LeaveAgainstAllowedDirection,
|
||||
InverseAccessRestrictionFlag = 127,
|
||||
AccessRestrictionFlag = 128,
|
||||
AccessRestrictionPenalty = 129
|
||||
};
|
||||
|
||||
struct TurnInstructionsClass
|
||||
{
|
||||
TurnInstructionsClass() = delete;
|
||||
TurnInstructionsClass(const TurnInstructionsClass &) = delete;
|
||||
|
||||
static inline TurnInstruction GetTurnDirectionOfInstruction(const double angle)
|
||||
{
|
||||
if (angle >= 23 && angle < 67)
|
||||
{
|
||||
return TurnInstruction::TurnSharpRight;
|
||||
}
|
||||
if (angle >= 67 && angle < 113)
|
||||
{
|
||||
return TurnInstruction::TurnRight;
|
||||
}
|
||||
if (angle >= 113 && angle < 158)
|
||||
{
|
||||
return TurnInstruction::TurnSlightRight;
|
||||
}
|
||||
if (angle >= 158 && angle < 202)
|
||||
{
|
||||
return TurnInstruction::GoStraight;
|
||||
}
|
||||
if (angle >= 202 && angle < 248)
|
||||
{
|
||||
return TurnInstruction::TurnSlightLeft;
|
||||
}
|
||||
if (angle >= 248 && angle < 292)
|
||||
{
|
||||
return TurnInstruction::TurnLeft;
|
||||
}
|
||||
if (angle >= 292 && angle < 336)
|
||||
{
|
||||
return TurnInstruction::TurnSharpLeft;
|
||||
}
|
||||
return TurnInstruction::UTurn;
|
||||
}
|
||||
|
||||
static inline bool TurnIsNecessary(const TurnInstruction turn_instruction)
|
||||
{
|
||||
if (TurnInstruction::NoTurn == turn_instruction ||
|
||||
TurnInstruction::StayOnRoundAbout == turn_instruction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* TURN_INSTRUCTIONS_HPP */
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef API_GRAMMAR_HPP
|
||||
#define API_GRAMMAR_HPP
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/qi_action.hpp>
|
||||
|
||||
namespace qi = boost::spirit::qi;
|
||||
|
||||
template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Iterator>
|
||||
{
|
||||
explicit APIGrammar(HandlerT *h) : APIGrammar::base_type(api_call), handler(h)
|
||||
{
|
||||
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
|
||||
-query;
|
||||
query = ('?') >> +(zoom | output | jsonp | checksum | uturns | location_with_options | destination_with_options | source_with_options | cmp |
|
||||
language | instruction | geometry | alt_route | old_API | num_results |
|
||||
matching_beta | gps_precision | classify | locs);
|
||||
// all combinations of timestamp, uturn, hint and bearing without duplicates
|
||||
t_u = (u >> -timestamp) | (timestamp >> -u);
|
||||
t_h = (hint >> -timestamp) | (timestamp >> -hint);
|
||||
u_h = (u >> -hint) | (hint >> -u);
|
||||
t_u_h = (hint >> -t_u) | (u >> -t_h) | (timestamp >> -u_h);
|
||||
location_options = (bearing >> -t_u_h) | (t_u_h >> -bearing) | //
|
||||
(u >> bearing >> -t_h) | (timestamp >> bearing >> -u_h) | (hint >> bearing >> t_u) | //
|
||||
(t_h >> bearing >> -u) | (u_h >> bearing >> -timestamp) | (t_u >> bearing >> -hint);
|
||||
location_with_options = location >> -location_options;
|
||||
source_with_options = source >> -location_options;
|
||||
destination_with_options = destination >> -location_options;
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
|
||||
qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >>
|
||||
string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
|
||||
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
|
||||
stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
|
||||
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
|
||||
qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
|
||||
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
|
||||
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
|
||||
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
|
||||
location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >>
|
||||
(qi::double_ >> qi::lit(',') >>
|
||||
qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
|
||||
destination = (-qi::lit('&')) >> qi::lit("dst") >> '=' >>
|
||||
(qi::double_ >> qi::lit(',') >>
|
||||
qi::double_)[boost::bind(&HandlerT::addDestination, handler, ::_1)];
|
||||
source = (-qi::lit('&')) >> qi::lit("src") >> '=' >>
|
||||
(qi::double_ >> qi::lit(',') >>
|
||||
qi::double_)[boost::bind(&HandlerT::addSource, handler, ::_1)];
|
||||
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
|
||||
stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
||||
timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
|
||||
qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
|
||||
bearing = (-qi::lit('&')) >> qi::lit("b") >> '=' >>
|
||||
(qi::int_ >> -(qi::lit(',') >> qi::int_ | qi::attr(10)))[boost::bind(&HandlerT::addBearing, handler, ::_1, ::_2, ::_3)];
|
||||
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
|
||||
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setAllUTurns, handler, ::_1)];
|
||||
language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >>
|
||||
string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
|
||||
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
|
||||
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >>
|
||||
string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
|
||||
num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >>
|
||||
qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
|
||||
matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
|
||||
qi::float_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
|
||||
gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
|
||||
qi::float_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
|
||||
classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
|
||||
locs = (-qi::lit('&')) >> qi::lit("locs") >> '=' >>
|
||||
stringforPolyline[boost::bind(&HandlerT::getCoordinatesFromGeometry, handler, ::_1)];
|
||||
|
||||
string = +(qi::char_("a-zA-Z"));
|
||||
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
|
||||
stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
|
||||
(qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
|
||||
stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
|
||||
}
|
||||
|
||||
qi::rule<Iterator> api_call, query, location_options, location_with_options, destination_with_options, source_with_options, t_u, t_h, u_h, t_u_h;
|
||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location, destination, source,
|
||||
hint, timestamp, bearing, stringwithDot, stringwithPercent, language, geometry, cmp, alt_route, u,
|
||||
uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, instruction, stringforPolyline;
|
||||
|
||||
HandlerT *handler;
|
||||
};
|
||||
|
||||
#endif /* API_GRAMMAR_HPP */
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_HPP
|
||||
#define CONNECTION_HPP
|
||||
|
||||
#include "http/compression_type.hpp"
|
||||
#include "http/reply.hpp"
|
||||
#include "http/request.hpp"
|
||||
#include "request_parser.hpp"
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// workaround for incomplete std::shared_ptr compatibility in old boost versions
|
||||
#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
|
||||
|
||||
template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
class RequestHandler;
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
class Connection : public std::enable_shared_from_this<Connection>
|
||||
{
|
||||
public:
|
||||
explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
|
||||
Connection(const Connection &) = delete;
|
||||
Connection() = delete;
|
||||
|
||||
boost::asio::ip::tcp::socket &socket();
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start();
|
||||
|
||||
private:
|
||||
void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code &e);
|
||||
|
||||
std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
|
||||
const compression_type compression_type);
|
||||
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::ip::tcp::socket TCP_socket;
|
||||
RequestHandler &request_handler;
|
||||
RequestParser request_parser;
|
||||
boost::array<char, 8192> incoming_data_buffer;
|
||||
request current_request;
|
||||
reply current_reply;
|
||||
std::vector<char> compressed_output;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // CONNECTION_HPP
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef COMPRESSION_TYPE_HPP
|
||||
#define COMPRESSION_TYPE_HPP
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
enum compression_type
|
||||
{
|
||||
no_compression,
|
||||
gzip_rfc1952,
|
||||
deflate_rfc1951
|
||||
};
|
||||
}
|
||||
|
||||
#endif // COMPRESSION_TYPE_HPP
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HEADER_HPP
|
||||
#define HEADER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace http
|
||||
{
|
||||
struct header
|
||||
{
|
||||
// explicitly use default copy c'tor as adding move c'tor
|
||||
header &operator=(const header &other) = default;
|
||||
header(std::string name, std::string value) : name(std::move(name)), value(std::move(value)) {}
|
||||
header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
|
||||
|
||||
void clear()
|
||||
{
|
||||
name.clear();
|
||||
value.clear();
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // HEADER_HPP
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REPLY_HPP
|
||||
#define REPLY_HPP
|
||||
|
||||
#include "header.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace http
|
||||
{
|
||||
class reply
|
||||
{
|
||||
public:
|
||||
enum status_type
|
||||
{
|
||||
ok = 200,
|
||||
bad_request = 400,
|
||||
internal_server_error = 500
|
||||
} status;
|
||||
|
||||
std::vector<header> headers;
|
||||
std::vector<boost::asio::const_buffer> to_buffers();
|
||||
std::vector<boost::asio::const_buffer> headers_to_buffers();
|
||||
std::vector<char> content;
|
||||
static reply stock_reply(const status_type status);
|
||||
void set_size(const std::size_t size);
|
||||
void set_uncompressed_size();
|
||||
|
||||
reply();
|
||||
|
||||
private:
|
||||
std::string status_to_string(reply::status_type status);
|
||||
boost::asio::const_buffer status_to_buffer(reply::status_type status);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // REPLY_HPP
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_HPP
|
||||
#define REQUEST_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
struct request
|
||||
{
|
||||
std::string uri;
|
||||
std::string referrer;
|
||||
std::string agent;
|
||||
boost::asio::ip::address endpoint;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // REQUEST_HPP
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_HANDLER_HPP
|
||||
#define REQUEST_HANDLER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
template <typename Iterator, class HandlerT> struct APIGrammar;
|
||||
struct RouteParameters;
|
||||
class OSRM;
|
||||
|
||||
namespace http
|
||||
{
|
||||
class reply;
|
||||
struct request;
|
||||
}
|
||||
|
||||
class RequestHandler
|
||||
{
|
||||
|
||||
public:
|
||||
using APIGrammarParser = APIGrammar<std::string::iterator, RouteParameters>;
|
||||
|
||||
RequestHandler();
|
||||
RequestHandler(const RequestHandler &) = delete;
|
||||
|
||||
void handle_request(const http::request ¤t_request, http::reply ¤t_reply);
|
||||
void RegisterRoutingMachine(OSRM *osrm);
|
||||
|
||||
private:
|
||||
OSRM *routing_machine;
|
||||
};
|
||||
|
||||
#endif // REQUEST_HANDLER_HPP
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_PARSER_HPP
|
||||
#define REQUEST_PARSER_HPP
|
||||
|
||||
#include "http/compression_type.hpp"
|
||||
#include "http/header.hpp"
|
||||
#include "../data_structures/tribool.hpp"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
struct request;
|
||||
|
||||
class RequestParser
|
||||
{
|
||||
public:
|
||||
RequestParser();
|
||||
|
||||
std::tuple<osrm::tribool, compression_type>
|
||||
parse(request ¤t_request, char *begin, char *end);
|
||||
|
||||
private:
|
||||
osrm::tribool consume(request ¤t_request, const char input);
|
||||
|
||||
bool is_char(const int character) const;
|
||||
|
||||
bool is_CTL(const int character) const;
|
||||
|
||||
bool is_special(const int character) const;
|
||||
|
||||
bool is_digit(const int character) const;
|
||||
|
||||
enum class internal_state : unsigned char
|
||||
{
|
||||
method_start,
|
||||
method,
|
||||
uri_start,
|
||||
uri,
|
||||
http_version_h,
|
||||
http_version_t_1,
|
||||
http_version_t_2,
|
||||
http_version_p,
|
||||
http_version_slash,
|
||||
http_version_major_start,
|
||||
http_version_major,
|
||||
http_version_minor_start,
|
||||
http_version_minor,
|
||||
expecting_newline_1,
|
||||
header_line_start,
|
||||
header_lws,
|
||||
header_name,
|
||||
space_before_header_value,
|
||||
header_value,
|
||||
expecting_newline_2,
|
||||
expecting_newline_3,
|
||||
post_O,
|
||||
post_S,
|
||||
post_T,
|
||||
post_request
|
||||
} state;
|
||||
|
||||
header current_header;
|
||||
compression_type selected_compression;
|
||||
bool is_post_header;
|
||||
int content_length;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // REQUEST_PARSER_HPP
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SERVER_HPP
|
||||
#define SERVER_HPP
|
||||
|
||||
#include "connection.hpp"
|
||||
#include "request_handler.hpp"
|
||||
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../util/simple_logger.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
// Note: returns a shared instead of a unique ptr as it is captured in a lambda somewhere else
|
||||
static std::shared_ptr<Server>
|
||||
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
|
||||
{
|
||||
SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
|
||||
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
|
||||
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
|
||||
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
|
||||
}
|
||||
|
||||
explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
|
||||
: thread_pool_size(thread_pool_size), acceptor(io_service),
|
||||
new_connection(std::make_shared<http::Connection>(io_service, request_handler))
|
||||
{
|
||||
const auto port_string = std::to_string(port);
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service);
|
||||
boost::asio::ip::tcp::resolver::query query(address, port_string);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
|
||||
acceptor.open(endpoint.protocol());
|
||||
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor.bind(endpoint);
|
||||
acceptor.listen();
|
||||
acceptor.async_accept(
|
||||
new_connection->socket(),
|
||||
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
std::vector<std::shared_ptr<std::thread>> threads;
|
||||
for (unsigned i = 0; i < thread_pool_size; ++i)
|
||||
{
|
||||
std::shared_ptr<std::thread> thread = std::make_shared<std::thread>(
|
||||
boost::bind(&boost::asio::io_service::run, &io_service));
|
||||
threads.push_back(thread);
|
||||
}
|
||||
for (auto thread : threads)
|
||||
{
|
||||
thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() { io_service.stop(); }
|
||||
|
||||
RequestHandler &GetRequestHandlerPtr() { return request_handler; }
|
||||
|
||||
private:
|
||||
void HandleAccept(const boost::system::error_code &e)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
new_connection->start();
|
||||
new_connection = std::make_shared<http::Connection>(io_service, request_handler);
|
||||
acceptor.async_accept(
|
||||
new_connection->socket(),
|
||||
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned thread_pool_size;
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::tcp::acceptor acceptor;
|
||||
std::shared_ptr<http::Connection> new_connection;
|
||||
RequestHandler request_handler;
|
||||
};
|
||||
|
||||
#endif // SERVER_HPP
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BEARING_HPP
|
||||
#define BEARING_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace bearing
|
||||
{
|
||||
inline std::string get(const double heading)
|
||||
{
|
||||
BOOST_ASSERT(heading >= 0);
|
||||
BOOST_ASSERT(heading <= 360);
|
||||
|
||||
if (heading <= 22.5)
|
||||
{
|
||||
return "N";
|
||||
}
|
||||
if (heading <= 67.5)
|
||||
{
|
||||
return "NE";
|
||||
}
|
||||
if (heading <= 112.5)
|
||||
{
|
||||
return "E";
|
||||
}
|
||||
if (heading <= 157.5)
|
||||
{
|
||||
return "SE";
|
||||
}
|
||||
if (heading <= 202.5)
|
||||
{
|
||||
return "S";
|
||||
}
|
||||
if (heading <= 247.5)
|
||||
{
|
||||
return "SW";
|
||||
}
|
||||
if (heading <= 292.5)
|
||||
{
|
||||
return "W";
|
||||
}
|
||||
if (heading <= 337.5)
|
||||
{
|
||||
return "NW";
|
||||
}
|
||||
return "N";
|
||||
}
|
||||
|
||||
// Checks whether A is between B-range and B+range, all modulo 360
|
||||
// e.g. A = 5, B = 5, range = 10 == true
|
||||
// A = -6, B = 5, range = 10 == false
|
||||
// A = -2, B = 355, range = 10 == true
|
||||
// A = 6, B = 355, range = 10 == false
|
||||
// A = 355, B = -2, range = 10 == true
|
||||
//
|
||||
// @param A the bearing to check, in degrees, 0-359, 0=north
|
||||
// @param B the bearing to check against, in degrees, 0-359, 0=north
|
||||
// @param range the number of degrees either side of B that A will still match
|
||||
// @return true if B-range <= A <= B+range, modulo 360
|
||||
inline bool CheckInBounds(const int A, const int B, const int range)
|
||||
{
|
||||
|
||||
if (range >= 180)
|
||||
return true;
|
||||
if (range <= 0)
|
||||
return false;
|
||||
|
||||
// Map both bearings into positive modulo 360 space
|
||||
const int normalized_B = (B < 0) ? (B % 360) + 360 : (B % 360);
|
||||
const int normalized_A = (A < 0) ? (A % 360) + 360 : (A % 360);
|
||||
|
||||
if (normalized_B - range < 0)
|
||||
{
|
||||
return (normalized_B - range + 360 <= normalized_A && normalized_A < 360) ||
|
||||
(0 <= normalized_A && normalized_A <= normalized_B + range);
|
||||
}
|
||||
else if (normalized_B + range > 360)
|
||||
{
|
||||
return (normalized_B - range <= normalized_A && normalized_A < 360) ||
|
||||
(0 <= normalized_A && normalized_A <= normalized_B + range - 360);
|
||||
}
|
||||
else
|
||||
{
|
||||
return normalized_B - range <= normalized_A && normalized_A <= normalized_B + range;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BEARING_HPP
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BINARY_HEAP_H
|
||||
#define BINARY_HEAP_H
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
template <typename NodeID, typename Key> class ArrayStorage
|
||||
{
|
||||
public:
|
||||
explicit ArrayStorage(size_t size) : positions(size, 0) {}
|
||||
|
||||
~ArrayStorage() {}
|
||||
|
||||
Key &operator[](NodeID node) { return positions[node]; }
|
||||
|
||||
Key peek_index(const NodeID node) const { return positions[node]; }
|
||||
|
||||
void Clear() {}
|
||||
|
||||
private:
|
||||
std::vector<Key> positions;
|
||||
};
|
||||
|
||||
template <typename NodeID, typename Key> class MapStorage
|
||||
{
|
||||
public:
|
||||
explicit MapStorage(size_t) {}
|
||||
|
||||
Key &operator[](NodeID node) { return nodes[node]; }
|
||||
|
||||
void Clear() { nodes.clear(); }
|
||||
|
||||
Key peek_index(const NodeID node) const
|
||||
{
|
||||
const auto iter = nodes.find(node);
|
||||
if (nodes.end() != iter)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return std::numeric_limits<Key>::max();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<NodeID, Key> nodes;
|
||||
};
|
||||
|
||||
template <typename NodeID, typename Key> class UnorderedMapStorage
|
||||
{
|
||||
public:
|
||||
explicit UnorderedMapStorage(size_t) { nodes.rehash(1000); }
|
||||
|
||||
Key &operator[](const NodeID node) { return nodes[node]; }
|
||||
|
||||
Key peek_index(const NodeID node) const
|
||||
{
|
||||
const auto iter = nodes.find(node);
|
||||
if (std::end(nodes) != iter)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return std::numeric_limits<Key>::max();
|
||||
}
|
||||
|
||||
Key const &operator[](const NodeID node) const
|
||||
{
|
||||
auto iter = nodes.find(node);
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void Clear() { nodes.clear(); }
|
||||
|
||||
private:
|
||||
std::unordered_map<NodeID, Key> nodes;
|
||||
};
|
||||
|
||||
template <typename NodeID,
|
||||
typename Key,
|
||||
typename Weight,
|
||||
typename Data,
|
||||
typename IndexStorage = ArrayStorage<NodeID, NodeID>>
|
||||
class BinaryHeap
|
||||
{
|
||||
private:
|
||||
BinaryHeap(const BinaryHeap &right);
|
||||
void operator=(const BinaryHeap &right);
|
||||
|
||||
public:
|
||||
using WeightType = Weight;
|
||||
using DataType = Data;
|
||||
|
||||
explicit BinaryHeap(size_t maxID) : node_index(maxID) { Clear(); }
|
||||
|
||||
void Clear()
|
||||
{
|
||||
heap.resize(1);
|
||||
inserted_nodes.clear();
|
||||
heap[0].weight = std::numeric_limits<Weight>::min();
|
||||
node_index.Clear();
|
||||
}
|
||||
|
||||
std::size_t Size() const { return (heap.size() - 1); }
|
||||
|
||||
bool Empty() const { return 0 == Size(); }
|
||||
|
||||
void Insert(NodeID node, Weight weight, const Data &data)
|
||||
{
|
||||
HeapElement element;
|
||||
element.index = static_cast<NodeID>(inserted_nodes.size());
|
||||
element.weight = weight;
|
||||
const Key key = static_cast<Key>(heap.size());
|
||||
heap.emplace_back(element);
|
||||
inserted_nodes.emplace_back(node, key, weight, data);
|
||||
node_index[node] = element.index;
|
||||
Upheap(key);
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
Data &GetData(NodeID node)
|
||||
{
|
||||
const Key index = node_index.peek_index(node);
|
||||
return inserted_nodes[index].data;
|
||||
}
|
||||
|
||||
Data const &GetData(NodeID node) const
|
||||
{
|
||||
const Key index = node_index.peek_index(node);
|
||||
return inserted_nodes[index].data;
|
||||
}
|
||||
|
||||
Weight &GetKey(NodeID node)
|
||||
{
|
||||
const Key index = node_index[node];
|
||||
return inserted_nodes[index].weight;
|
||||
}
|
||||
|
||||
bool WasRemoved(const NodeID node) const
|
||||
{
|
||||
BOOST_ASSERT(WasInserted(node));
|
||||
const Key index = node_index.peek_index(node);
|
||||
return inserted_nodes[index].key == 0;
|
||||
}
|
||||
|
||||
bool WasInserted(const NodeID node) const
|
||||
{
|
||||
const auto index = node_index.peek_index(node);
|
||||
if (index >= static_cast<decltype(index)>(inserted_nodes.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return inserted_nodes[index].node == node;
|
||||
}
|
||||
|
||||
NodeID Min() const
|
||||
{
|
||||
BOOST_ASSERT(heap.size() > 1);
|
||||
return inserted_nodes[heap[1].index].node;
|
||||
}
|
||||
|
||||
Weight MinKey() const {
|
||||
BOOST_ASSERT(heap.size() > 1);
|
||||
return heap[1].weight;
|
||||
}
|
||||
|
||||
NodeID DeleteMin()
|
||||
{
|
||||
BOOST_ASSERT(heap.size() > 1);
|
||||
const Key removedIndex = heap[1].index;
|
||||
heap[1] = heap[heap.size() - 1];
|
||||
heap.pop_back();
|
||||
if (heap.size() > 1)
|
||||
{
|
||||
Downheap(1);
|
||||
}
|
||||
inserted_nodes[removedIndex].key = 0;
|
||||
CheckHeap();
|
||||
return inserted_nodes[removedIndex].node;
|
||||
}
|
||||
|
||||
void DeleteAll()
|
||||
{
|
||||
auto iend = heap.end();
|
||||
for (auto i = heap.begin() + 1; i != iend; ++i)
|
||||
{
|
||||
inserted_nodes[i->index].key = 0;
|
||||
}
|
||||
heap.resize(1);
|
||||
heap[0].weight = (std::numeric_limits<Weight>::min)();
|
||||
}
|
||||
|
||||
void DecreaseKey(NodeID node, Weight weight)
|
||||
{
|
||||
BOOST_ASSERT(std::numeric_limits<NodeID>::max() != node);
|
||||
const Key &index = node_index.peek_index(node);
|
||||
Key &key = inserted_nodes[index].key;
|
||||
BOOST_ASSERT(key >= 0);
|
||||
|
||||
inserted_nodes[index].weight = weight;
|
||||
heap[key].weight = weight;
|
||||
Upheap(key);
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
private:
|
||||
class HeapNode
|
||||
{
|
||||
public:
|
||||
HeapNode(NodeID n, Key k, Weight w, Data d) : node(n), key(k), weight(w), data(std::move(d))
|
||||
{
|
||||
}
|
||||
|
||||
NodeID node;
|
||||
Key key;
|
||||
Weight weight;
|
||||
Data data;
|
||||
};
|
||||
struct HeapElement
|
||||
{
|
||||
Key index;
|
||||
Weight weight;
|
||||
};
|
||||
|
||||
std::vector<HeapNode> inserted_nodes;
|
||||
std::vector<HeapElement> heap;
|
||||
IndexStorage node_index;
|
||||
|
||||
void Downheap(Key key)
|
||||
{
|
||||
const Key droppingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
const Key heap_size = static_cast<Key>(heap.size());
|
||||
Key nextKey = key << 1;
|
||||
while (nextKey < heap_size)
|
||||
{
|
||||
const Key nextKeyOther = nextKey + 1;
|
||||
if ((nextKeyOther < heap_size) && (heap[nextKey].weight > heap[nextKeyOther].weight))
|
||||
{
|
||||
nextKey = nextKeyOther;
|
||||
}
|
||||
if (weight <= heap[nextKey].weight)
|
||||
{
|
||||
break;
|
||||
}
|
||||
heap[key] = heap[nextKey];
|
||||
inserted_nodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey <<= 1;
|
||||
}
|
||||
heap[key].index = droppingIndex;
|
||||
heap[key].weight = weight;
|
||||
inserted_nodes[droppingIndex].key = key;
|
||||
}
|
||||
|
||||
void Upheap(Key key)
|
||||
{
|
||||
const Key risingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key >> 1;
|
||||
while (heap[nextKey].weight > weight)
|
||||
{
|
||||
BOOST_ASSERT(nextKey != 0);
|
||||
heap[key] = heap[nextKey];
|
||||
inserted_nodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey >>= 1;
|
||||
}
|
||||
heap[key].index = risingIndex;
|
||||
heap[key].weight = weight;
|
||||
inserted_nodes[risingIndex].key = key;
|
||||
}
|
||||
|
||||
void CheckHeap()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (std::size_t i = 2; i < heap.size(); ++i)
|
||||
{
|
||||
BOOST_ASSERT(heap[i].weight >= heap[i >> 1].weight);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BINARY_HEAP_H
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CAST_HPP
|
||||
#define CAST_HPP
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
namespace cast
|
||||
{
|
||||
template <typename Enumeration>
|
||||
inline auto enum_to_underlying(Enumeration const value) ->
|
||||
typename std::underlying_type<Enumeration>::type
|
||||
{
|
||||
return static_cast<typename std::underlying_type<Enumeration>::type>(value);
|
||||
}
|
||||
|
||||
template <typename T, int Precision = 6> inline std::string to_string_with_precision(const T x)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "integral or floating point type required");
|
||||
|
||||
std::ostringstream out;
|
||||
out << std::fixed << std::setprecision(Precision) << x;
|
||||
auto rv = out.str();
|
||||
|
||||
// Javascript has no separation of float / int, digits without a '.' are integral typed
|
||||
// X.Y.0 -> X.Y
|
||||
// X.0 -> X
|
||||
boost::trim_right_if(rv, boost::is_any_of("0"));
|
||||
boost::trim_right_if(rv, boost::is_any_of("."));
|
||||
// Note:
|
||||
// - assumes the locale to use '.' as digit separator
|
||||
// - this is not identical to: trim_right_if(rv, is_any_of('0 .'))
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CAST_HPP
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef COMPUTE_ANGLE_HPP
|
||||
#define COMPUTE_ANGLE_HPP
|
||||
|
||||
struct FixedPointCoordinate;
|
||||
|
||||
struct ComputeAngle
|
||||
{
|
||||
// Get angle of line segment (A,C)->(C,B)
|
||||
// atan2 magic, formerly cosine theorem
|
||||
static double OfThreeFixedPointCoordinates(const FixedPointCoordinate &first,
|
||||
const FixedPointCoordinate &second,
|
||||
const FixedPointCoordinate &third) noexcept;
|
||||
};
|
||||
|
||||
#endif // COMPUTE_ANGLE_HPP
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CONTAINER_HPP
|
||||
#define CONTAINER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// Culled by SFINAE if reserve does not exist or is not accessible
|
||||
template <typename T>
|
||||
constexpr auto has_resize_method(T &t) noexcept -> decltype(t.resize(0), bool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Used as fallback when SFINAE culls the template method
|
||||
constexpr bool has_resize_method(...) noexcept { return false; }
|
||||
}
|
||||
|
||||
template <typename Container> void sort_unique_resize(Container &vector) noexcept
|
||||
{
|
||||
std::sort(std::begin(vector), std::end(vector));
|
||||
const auto number_of_unique_elements =
|
||||
std::unique(std::begin(vector), std::end(vector)) - std::begin(vector);
|
||||
if (detail::has_resize_method(vector))
|
||||
{
|
||||
vector.resize(number_of_unique_elements);
|
||||
}
|
||||
}
|
||||
|
||||
// template <typename T> inline void sort_unique_resize_shrink_vector(std::vector<T> &vector)
|
||||
// {
|
||||
// sort_unique_resize(vector);
|
||||
// vector.shrink_to_fit();
|
||||
// }
|
||||
|
||||
// template <typename T> inline void remove_consecutive_duplicates_from_vector(std::vector<T>
|
||||
// &vector)
|
||||
// {
|
||||
// const auto number_of_unique_elements = std::unique(vector.begin(), vector.end()) -
|
||||
// vector.begin();
|
||||
// vector.resize(number_of_unique_elements);
|
||||
// }
|
||||
|
||||
template <typename ForwardIterator, typename Function>
|
||||
Function for_each_pair(ForwardIterator begin, ForwardIterator end, Function function)
|
||||
{
|
||||
if (begin == end)
|
||||
{
|
||||
return function;
|
||||
}
|
||||
|
||||
auto next = begin;
|
||||
next = std::next(next);
|
||||
|
||||
while (next != end)
|
||||
{
|
||||
function(*begin, *next);
|
||||
begin = std::next(begin);
|
||||
next = std::next(next);
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
template <class ContainerT, typename Function>
|
||||
Function for_each_pair(ContainerT &container, Function function)
|
||||
{
|
||||
return for_each_pair(std::begin(container), std::end(container), function);
|
||||
}
|
||||
|
||||
template <class Container> void append_to_container(Container &&) {}
|
||||
|
||||
template <class Container, typename T, typename... Args>
|
||||
void append_to_container(Container &&container, T value, Args &&... args)
|
||||
{
|
||||
container.emplace_back(value);
|
||||
append_to_container(std::forward<Container>(container), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace osrm
|
||||
#endif /* CONTAINER_HPP */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef COORDINATE_CALCULATION
|
||||
#define COORDINATE_CALCULATION
|
||||
|
||||
struct FixedPointCoordinate;
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace coordinate_calculation
|
||||
{
|
||||
double
|
||||
haversine_distance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
double haversine_distance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
float great_circle_distance(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
|
||||
float great_circle_distance(const int lat1, const int lon1, const int lat2, const int lon2);
|
||||
|
||||
void lat_or_lon_to_string(const int value, std::string &output);
|
||||
|
||||
float perpendicular_distance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location);
|
||||
|
||||
float perpendicular_distance(const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
float perpendicular_distance_from_projected_coordinate(
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
const std::pair<double, double> &projected_coordinate);
|
||||
|
||||
float perpendicular_distance_from_projected_coordinate(
|
||||
const FixedPointCoordinate &segment_source,
|
||||
const FixedPointCoordinate &segment_target,
|
||||
const FixedPointCoordinate &query_location,
|
||||
const std::pair<double, double> &projected_coordinate,
|
||||
FixedPointCoordinate &nearest_location,
|
||||
float &ratio);
|
||||
|
||||
float deg_to_rad(const float degree);
|
||||
float rad_to_deg(const float radian);
|
||||
|
||||
float bearing(const FixedPointCoordinate &first_coordinate,
|
||||
const FixedPointCoordinate &second_coordinate);
|
||||
}
|
||||
|
||||
#endif // COORDINATE_CALCULATION
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DATASTORE_OPTIONS_HPP
|
||||
#define DATASTORE_OPTIONS_HPP
|
||||
|
||||
#include "util/version.hpp"
|
||||
#include "ini_file.hpp"
|
||||
#include "osrm_exception.hpp"
|
||||
#include "simple_logger.hpp"
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// generate boost::program_options object for the routing part
|
||||
bool GenerateDataStoreOptions(const int argc, const char *argv[], std::unordered_map<std::string, boost::filesystem::path> &paths)
|
||||
{
|
||||
// declare a group of options that will be allowed only on command line
|
||||
boost::program_options::options_description generic_options("Options");
|
||||
generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message")(
|
||||
"springclean,s", "Remove all regions in shared memory")(
|
||||
"config,c", boost::program_options::value<boost::filesystem::path>(&paths["config"])
|
||||
->default_value("server.ini"),
|
||||
"Path to a configuration file");
|
||||
|
||||
// declare a group of options that will be allowed both on command line
|
||||
// as well as in a config file
|
||||
boost::program_options::options_description config_options("Configuration");
|
||||
config_options.add_options()(
|
||||
"hsgrdata", boost::program_options::value<boost::filesystem::path>(&paths["hsgrdata"]),
|
||||
".hsgr file")("nodesdata",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["nodesdata"]),
|
||||
".nodes file")(
|
||||
"edgesdata", boost::program_options::value<boost::filesystem::path>(&paths["edgesdata"]),
|
||||
".edges file")("geometry",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["geometry"]),
|
||||
".geometry file")(
|
||||
"ramindex", boost::program_options::value<boost::filesystem::path>(&paths["ramindex"]),
|
||||
".ramIndex file")(
|
||||
"fileindex", boost::program_options::value<boost::filesystem::path>(&paths["fileindex"]),
|
||||
".fileIndex file")("core",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["core"]),
|
||||
".core file")(
|
||||
"namesdata", boost::program_options::value<boost::filesystem::path>(&paths["namesdata"]),
|
||||
".names file")("timestamp",
|
||||
boost::program_options::value<boost::filesystem::path>(&paths["timestamp"]),
|
||||
".timestamp file");
|
||||
|
||||
// hidden options, will be allowed both on command line and in config
|
||||
// file, but will not be shown to the user
|
||||
boost::program_options::options_description hidden_options("Hidden options");
|
||||
hidden_options.add_options()(
|
||||
"base,b", boost::program_options::value<boost::filesystem::path>(&paths["base"]),
|
||||
"base path to .osrm file");
|
||||
|
||||
// positional option
|
||||
boost::program_options::positional_options_description positional_options;
|
||||
positional_options.add("base", 1);
|
||||
|
||||
// combine above options for parsing
|
||||
boost::program_options::options_description cmdline_options;
|
||||
cmdline_options.add(generic_options).add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description config_file_options;
|
||||
config_file_options.add(config_options).add(hidden_options);
|
||||
|
||||
boost::program_options::options_description visible_options(
|
||||
boost::filesystem::basename(argv[0]) + " [<options>] <configuration>");
|
||||
visible_options.add(generic_options).add(config_options);
|
||||
|
||||
// parse command line options
|
||||
boost::program_options::variables_map option_variables;
|
||||
boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
|
||||
.options(cmdline_options)
|
||||
.positional(positional_options)
|
||||
.run(),
|
||||
option_variables);
|
||||
|
||||
if (option_variables.count("version"))
|
||||
{
|
||||
SimpleLogger().Write() << OSRM_VERSION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (option_variables.count("help"))
|
||||
{
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::program_options::notify(option_variables);
|
||||
|
||||
const bool parameter_present =
|
||||
(paths.find("hsgrdata") != paths.end() &&
|
||||
!paths.find("hsgrdata")->second.string().empty()) ||
|
||||
(paths.find("nodesdata") != paths.end() &&
|
||||
!paths.find("nodesdata")->second.string().empty()) ||
|
||||
(paths.find("edgesdata") != paths.end() &&
|
||||
!paths.find("edgesdata")->second.string().empty()) ||
|
||||
(paths.find("geometry") != paths.end() &&
|
||||
!paths.find("geometry")->second.string().empty()) ||
|
||||
(paths.find("ramindex") != paths.end() &&
|
||||
!paths.find("ramindex")->second.string().empty()) ||
|
||||
(paths.find("fileindex") != paths.end() &&
|
||||
!paths.find("fileindex")->second.string().empty()) ||
|
||||
(paths.find("core") != paths.end() && !paths.find("core")->second.string().empty()) ||
|
||||
(paths.find("timestamp") != paths.end() &&
|
||||
!paths.find("timestamp")->second.string().empty());
|
||||
|
||||
if (parameter_present)
|
||||
{
|
||||
if ((paths.find("config") != paths.end() &&
|
||||
boost::filesystem::is_regular_file(paths.find("config")->second)) ||
|
||||
option_variables.count("base"))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << "conflicting parameters";
|
||||
SimpleLogger().Write() << visible_options;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// parse config file
|
||||
auto path_iterator = paths.find("config");
|
||||
if (path_iterator != paths.end() && boost::filesystem::is_regular_file(path_iterator->second) &&
|
||||
!option_variables.count("base"))
|
||||
{
|
||||
SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string();
|
||||
std::string ini_file_contents = read_file_lower_content(path_iterator->second);
|
||||
std::stringstream config_stream(ini_file_contents);
|
||||
boost::program_options::store(parse_config_file(config_stream, config_file_options),
|
||||
option_variables);
|
||||
boost::program_options::notify(option_variables);
|
||||
}
|
||||
else if (option_variables.count("base"))
|
||||
{
|
||||
path_iterator = paths.find("base");
|
||||
BOOST_ASSERT(paths.end() != path_iterator);
|
||||
std::string base_string = path_iterator->second.string();
|
||||
|
||||
path_iterator = paths.find("hsgrdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".hsgr";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("nodesdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".nodes";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("edgesdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".edges";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("geometry");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".geometry";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("ramindex");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".ramIndex";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("fileindex");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".fileIndex";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("core");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".core";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("namesdata");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".names";
|
||||
}
|
||||
|
||||
path_iterator = paths.find("timestamp");
|
||||
if (path_iterator != paths.end())
|
||||
{
|
||||
path_iterator->second = base_string + ".timestamp";
|
||||
}
|
||||
}
|
||||
|
||||
path_iterator = paths.find("hsgrdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .hsgr file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("nodesdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .nodes file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("edgesdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .edges file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("geometry");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .geometry file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("ramindex");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .ramindex file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("fileindex");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .fileindex file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("namesdata");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .names file must be specified");
|
||||
}
|
||||
|
||||
path_iterator = paths.find("timestamp");
|
||||
if (path_iterator == paths.end() || path_iterator->second.string().empty() ||
|
||||
!boost::filesystem::is_regular_file(path_iterator->second))
|
||||
{
|
||||
throw osrm::exception("valid .timestamp file must be specified");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* DATASTORE_OPTIONS_HPP */
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DEALLOCATING_VECTOR_HPP
|
||||
#define DEALLOCATING_VECTOR_HPP
|
||||
|
||||
#include "../util/integer_range.hpp"
|
||||
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
template <typename ElementT> struct ConstDeallocatingVectorIteratorState
|
||||
{
|
||||
ConstDeallocatingVectorIteratorState()
|
||||
: index(std::numeric_limits<std::size_t>::max()), bucket_list(nullptr)
|
||||
{
|
||||
}
|
||||
explicit ConstDeallocatingVectorIteratorState(const ConstDeallocatingVectorIteratorState &r)
|
||||
: index(r.index), bucket_list(r.bucket_list)
|
||||
{
|
||||
}
|
||||
explicit ConstDeallocatingVectorIteratorState(const std::size_t idx,
|
||||
const std::vector<ElementT *> *input_list)
|
||||
: index(idx), bucket_list(input_list)
|
||||
{
|
||||
}
|
||||
std::size_t index;
|
||||
const std::vector<ElementT *> *bucket_list;
|
||||
|
||||
ConstDeallocatingVectorIteratorState &operator=(const ConstDeallocatingVectorIteratorState &other)
|
||||
{
|
||||
index = other.index;
|
||||
bucket_list = other.bucket_list;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementT> struct DeallocatingVectorIteratorState
|
||||
{
|
||||
DeallocatingVectorIteratorState()
|
||||
: index(std::numeric_limits<std::size_t>::max()), bucket_list(nullptr)
|
||||
{
|
||||
}
|
||||
explicit DeallocatingVectorIteratorState(const DeallocatingVectorIteratorState &r)
|
||||
: index(r.index), bucket_list(r.bucket_list)
|
||||
{
|
||||
}
|
||||
explicit DeallocatingVectorIteratorState(const std::size_t idx,
|
||||
std::vector<ElementT *> *input_list)
|
||||
: index(idx), bucket_list(input_list)
|
||||
{
|
||||
}
|
||||
std::size_t index;
|
||||
std::vector<ElementT *> *bucket_list;
|
||||
|
||||
DeallocatingVectorIteratorState &operator=(const DeallocatingVectorIteratorState &other)
|
||||
{
|
||||
index = other.index;
|
||||
bucket_list = other.bucket_list;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
|
||||
class ConstDeallocatingVectorIterator
|
||||
: public boost::iterator_facade<ConstDeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>,
|
||||
ElementT,
|
||||
std::random_access_iterator_tag>
|
||||
{
|
||||
ConstDeallocatingVectorIteratorState<ElementT> current_state;
|
||||
|
||||
public:
|
||||
ConstDeallocatingVectorIterator() {}
|
||||
ConstDeallocatingVectorIterator(std::size_t idx, const std::vector<ElementT *> *input_list)
|
||||
: current_state(idx, input_list)
|
||||
{
|
||||
}
|
||||
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void advance(std::size_t n) { current_state.index += n; }
|
||||
|
||||
void increment() { advance(1); }
|
||||
|
||||
void decrement() { advance(-1); }
|
||||
|
||||
bool equal(ConstDeallocatingVectorIterator const &other) const
|
||||
{
|
||||
return current_state.index == other.current_state.index;
|
||||
}
|
||||
|
||||
std::ptrdiff_t distance_to(ConstDeallocatingVectorIterator const &other) const
|
||||
{
|
||||
// it is important to implement it 'other minus this'. otherwise sorting breaks
|
||||
return other.current_state.index - current_state.index;
|
||||
}
|
||||
|
||||
ElementT &dereference() const
|
||||
{
|
||||
const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
|
||||
return (current_state.bucket_list->at(current_bucket)[current_index]);
|
||||
}
|
||||
|
||||
ElementT &operator[](const std::size_t index) const
|
||||
{
|
||||
const std::size_t current_bucket = (index + current_state.index) / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t current_index = (index + current_state.index) % ELEMENTS_PER_BLOCK;
|
||||
return (current_state.bucket_list->at(current_bucket)[current_index]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
|
||||
class DeallocatingVectorIterator
|
||||
: public boost::iterator_facade<DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>,
|
||||
ElementT,
|
||||
std::random_access_iterator_tag>
|
||||
{
|
||||
DeallocatingVectorIteratorState<ElementT> current_state;
|
||||
|
||||
public:
|
||||
DeallocatingVectorIterator() {}
|
||||
DeallocatingVectorIterator(std::size_t idx, std::vector<ElementT *> *input_list)
|
||||
: current_state(idx, input_list)
|
||||
{
|
||||
}
|
||||
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void advance(std::size_t n) { current_state.index += n; }
|
||||
|
||||
void increment() { advance(1); }
|
||||
|
||||
void decrement() { advance(-1); }
|
||||
|
||||
bool equal(DeallocatingVectorIterator const &other) const
|
||||
{
|
||||
return current_state.index == other.current_state.index;
|
||||
}
|
||||
|
||||
std::ptrdiff_t distance_to(DeallocatingVectorIterator const &other) const
|
||||
{
|
||||
// it is important to implement it 'other minus this'. otherwise sorting breaks
|
||||
return other.current_state.index - current_state.index;
|
||||
}
|
||||
|
||||
ElementT &dereference() const
|
||||
{
|
||||
const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
|
||||
return (current_state.bucket_list->at(current_bucket)[current_index]);
|
||||
}
|
||||
|
||||
ElementT &operator[](const std::size_t index) const
|
||||
{
|
||||
const std::size_t current_bucket = (index + current_state.index) / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t current_index = (index + current_state.index) % ELEMENTS_PER_BLOCK;
|
||||
return (current_state.bucket_list->at(current_bucket)[current_index]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
|
||||
class DeallocatingVectorRemoveIterator
|
||||
: public boost::iterator_facade<DeallocatingVectorRemoveIterator<ElementT, ELEMENTS_PER_BLOCK>,
|
||||
ElementT,
|
||||
boost::forward_traversal_tag>
|
||||
{
|
||||
DeallocatingVectorIteratorState<ElementT> current_state;
|
||||
|
||||
public:
|
||||
DeallocatingVectorRemoveIterator(std::size_t idx, std::vector<ElementT *> *input_list)
|
||||
: current_state(idx, input_list)
|
||||
{
|
||||
}
|
||||
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment()
|
||||
{
|
||||
const std::size_t old_bucket = current_state.index / ELEMENTS_PER_BLOCK;
|
||||
|
||||
++current_state.index;
|
||||
const std::size_t new_bucket = current_state.index / ELEMENTS_PER_BLOCK;
|
||||
if (old_bucket != new_bucket)
|
||||
{
|
||||
// delete old bucket entry
|
||||
if (nullptr != current_state.bucket_list->at(old_bucket))
|
||||
{
|
||||
delete[] current_state.bucket_list->at(old_bucket);
|
||||
current_state.bucket_list->at(old_bucket) = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool equal(DeallocatingVectorRemoveIterator const &other) const
|
||||
{
|
||||
return current_state.index == other.current_state.index;
|
||||
}
|
||||
|
||||
std::ptrdiff_t distance_to(DeallocatingVectorRemoveIterator const &other) const
|
||||
{
|
||||
return other.current_state.index - current_state.index;
|
||||
}
|
||||
|
||||
ElementT &dereference() const
|
||||
{
|
||||
const std::size_t current_bucket = current_state.index / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t current_index = current_state.index % ELEMENTS_PER_BLOCK;
|
||||
return (current_state.bucket_list->at(current_bucket)[current_index]);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK>
|
||||
class DeallocatingVector;
|
||||
|
||||
template<typename T, std::size_t S>
|
||||
void swap(DeallocatingVector<T, S>& lhs, DeallocatingVector<T, S>& rhs);
|
||||
|
||||
template <typename ElementT, std::size_t ELEMENTS_PER_BLOCK = 8388608 / sizeof(ElementT)>
|
||||
class DeallocatingVector
|
||||
{
|
||||
std::size_t current_size;
|
||||
std::vector<ElementT *> bucket_list;
|
||||
|
||||
public:
|
||||
using iterator = DeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>;
|
||||
using const_iterator = ConstDeallocatingVectorIterator<ElementT, ELEMENTS_PER_BLOCK>;
|
||||
|
||||
// this forward-only iterator deallocates all buckets that have been visited
|
||||
using deallocation_iterator = DeallocatingVectorRemoveIterator<ElementT, ELEMENTS_PER_BLOCK>;
|
||||
|
||||
DeallocatingVector() : current_size(0)
|
||||
{
|
||||
bucket_list.emplace_back(new ElementT[ELEMENTS_PER_BLOCK]);
|
||||
}
|
||||
|
||||
~DeallocatingVector() { clear(); }
|
||||
|
||||
friend void swap<>(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK>& lhs, DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK>& rhs);
|
||||
|
||||
void swap(DeallocatingVector<ElementT, ELEMENTS_PER_BLOCK> &other)
|
||||
{
|
||||
std::swap(current_size, other.current_size);
|
||||
bucket_list.swap(other.bucket_list);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
// Delete[]'ing ptr's to all Buckets
|
||||
for (auto bucket : bucket_list)
|
||||
{
|
||||
if (nullptr != bucket)
|
||||
{
|
||||
delete[] bucket;
|
||||
bucket = nullptr;
|
||||
}
|
||||
}
|
||||
bucket_list.clear();
|
||||
bucket_list.shrink_to_fit();
|
||||
current_size = 0;
|
||||
}
|
||||
|
||||
void push_back(const ElementT &element)
|
||||
{
|
||||
const std::size_t current_capacity = capacity();
|
||||
if (current_size == current_capacity)
|
||||
{
|
||||
bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
|
||||
}
|
||||
|
||||
std::size_t current_index = size() % ELEMENTS_PER_BLOCK;
|
||||
bucket_list.back()[current_index] = element;
|
||||
++current_size;
|
||||
}
|
||||
|
||||
template <typename... Ts> void emplace_back(Ts &&... element)
|
||||
{
|
||||
const std::size_t current_capacity = capacity();
|
||||
if (current_size == current_capacity)
|
||||
{
|
||||
bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
|
||||
}
|
||||
|
||||
const std::size_t current_index = size() % ELEMENTS_PER_BLOCK;
|
||||
bucket_list.back()[current_index] = ElementT(std::forward<Ts>(element)...);
|
||||
++current_size;
|
||||
}
|
||||
|
||||
void reserve(const std::size_t) const { /* don't do anything */}
|
||||
|
||||
void resize(const std::size_t new_size)
|
||||
{
|
||||
if (new_size >= current_size)
|
||||
{
|
||||
while (capacity() < new_size)
|
||||
{
|
||||
bucket_list.push_back(new ElementT[ELEMENTS_PER_BLOCK]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // down-size
|
||||
const std::size_t number_of_necessary_buckets = 1 + (new_size / ELEMENTS_PER_BLOCK);
|
||||
for (const auto bucket_index :
|
||||
osrm::irange(number_of_necessary_buckets, bucket_list.size()))
|
||||
{
|
||||
if (nullptr != bucket_list[bucket_index])
|
||||
{
|
||||
delete[] bucket_list[bucket_index];
|
||||
}
|
||||
}
|
||||
bucket_list.resize(number_of_necessary_buckets);
|
||||
}
|
||||
current_size = new_size;
|
||||
}
|
||||
|
||||
std::size_t size() const { return current_size; }
|
||||
|
||||
std::size_t capacity() const { return bucket_list.size() * ELEMENTS_PER_BLOCK; }
|
||||
|
||||
iterator begin() { return iterator(static_cast<std::size_t>(0), &bucket_list); }
|
||||
|
||||
iterator end() { return iterator(size(), &bucket_list); }
|
||||
|
||||
deallocation_iterator dbegin()
|
||||
{
|
||||
return deallocation_iterator(static_cast<std::size_t>(0), &bucket_list);
|
||||
}
|
||||
|
||||
deallocation_iterator dend() { return deallocation_iterator(size(), &bucket_list); }
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(static_cast<std::size_t>(0), &bucket_list);
|
||||
}
|
||||
|
||||
const_iterator end() const { return const_iterator(size(), &bucket_list); }
|
||||
|
||||
ElementT &operator[](const std::size_t index)
|
||||
{
|
||||
const std::size_t _bucket = index / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t _index = index % ELEMENTS_PER_BLOCK;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
|
||||
ElementT &operator[](const std::size_t index) const
|
||||
{
|
||||
const std::size_t _bucket = index / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t _index = index % ELEMENTS_PER_BLOCK;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
|
||||
ElementT &back() const
|
||||
{
|
||||
const std::size_t _bucket = current_size / ELEMENTS_PER_BLOCK;
|
||||
const std::size_t _index = current_size % ELEMENTS_PER_BLOCK;
|
||||
return (bucket_list[_bucket][_index]);
|
||||
}
|
||||
|
||||
template <class InputIterator> void append(InputIterator first, const InputIterator last)
|
||||
{
|
||||
InputIterator position = first;
|
||||
while (position != last)
|
||||
{
|
||||
push_back(*position);
|
||||
++position;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, std::size_t S>
|
||||
void swap(DeallocatingVector<T, S>& lhs, DeallocatingVector<T, S>& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
#endif /* DEALLOCATING_VECTOR_HPP */
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_GEOMETRY_H
|
||||
#define DEBUG_GEOMETRY_H
|
||||
|
||||
#include "../contractor/contractor_options.hpp"
|
||||
#include "../data_structures/query_node.hpp"
|
||||
|
||||
#ifndef DEBUG_GEOMETRY
|
||||
|
||||
inline void DEBUG_GEOMETRY_START(ContractorConfig & /* config */) {}
|
||||
inline void DEBUG_GEOMETRY_EDGE(int /* new_segment_weight */ , double /* segment_length */,
|
||||
OSMNodeID /* previous_osm_node_id */, OSMNodeID /* this_osm_node_id */) {}
|
||||
inline void DEBUG_GEOMETRY_STOP() {}
|
||||
|
||||
inline void DEBUG_TURNS_START(const std::string & /* debug_turns_filename */) {}
|
||||
inline void DEBUG_TURN( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
|
||||
const FixedPointCoordinate & /* first_coordinate */, const int /* turn_angle */,
|
||||
const int /* turn_penalty */) {}
|
||||
inline void DEBUG_UTURN( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
|
||||
const int /* uturn_penalty */ ) {}
|
||||
inline void DEBUG_SIGNAL( const NodeID /* node */, const std::vector<QueryNode>& /* m_node_info_list */,
|
||||
const int /* signal_penalty */ ) {}
|
||||
|
||||
inline void DEBUG_TURNS_STOP() {}
|
||||
|
||||
#else // DEBUG_GEOMETRY
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "../include/osrm/coordinate.hpp"
|
||||
#include "../algorithms/coordinate_calculation.hpp"
|
||||
|
||||
boost::filesystem::ofstream debug_geometry_file;
|
||||
bool dg_output_debug_geometry = false;
|
||||
bool dg_first_debug_geometry = true;
|
||||
char dg_time_buffer[80];
|
||||
|
||||
boost::filesystem::ofstream dg_debug_turns_file;
|
||||
bool dg_output_turn_debug = false;
|
||||
bool dg_first_turn_debug = true;
|
||||
|
||||
inline void DEBUG_GEOMETRY_START(const ContractorConfig &config)
|
||||
{
|
||||
time_t raw_time;
|
||||
struct tm *timeinfo;
|
||||
time(&raw_time);
|
||||
timeinfo = localtime(&raw_time);
|
||||
strftime(dg_time_buffer, 80, "%Y-%m-%d %H:%M %Z", timeinfo);
|
||||
|
||||
dg_output_debug_geometry = config.debug_geometry_path != "";
|
||||
|
||||
if (dg_output_debug_geometry)
|
||||
{
|
||||
debug_geometry_file.open(config.debug_geometry_path, std::ios::binary);
|
||||
debug_geometry_file << "{\"type\":\"FeatureCollection\", \"features\":[" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DEBUG_GEOMETRY_EDGE(int new_segment_weight, double segment_length, OSMNodeID previous_osm_node_id, OSMNodeID this_osm_node_id)
|
||||
{
|
||||
if (dg_output_debug_geometry)
|
||||
{
|
||||
if (!dg_first_debug_geometry)
|
||||
debug_geometry_file << "," << std::endl;
|
||||
debug_geometry_file
|
||||
<< "{ \"type\":\"Feature\",\"properties\":{\"original\":false, "
|
||||
"\"weight\":"
|
||||
<< new_segment_weight / 10.0 << ",\"speed\":"
|
||||
<< static_cast<int>(
|
||||
std::floor((segment_length / new_segment_weight) * 10. * 3.6))
|
||||
<< ",";
|
||||
debug_geometry_file << "\"from_node\": " << previous_osm_node_id
|
||||
<< ", \"to_node\": " << this_osm_node_id << ",";
|
||||
debug_geometry_file << "\"timestamp\": \"" << dg_time_buffer << "\"},";
|
||||
debug_geometry_file
|
||||
<< "\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[!!"
|
||||
<< previous_osm_node_id << "!!],[!!" << this_osm_node_id << "!!]]}}"
|
||||
<< std::endl;
|
||||
dg_first_debug_geometry = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DEBUG_GEOMETRY_STOP()
|
||||
{
|
||||
if (dg_output_debug_geometry)
|
||||
{
|
||||
debug_geometry_file << std::endl << "]}" << std::endl;
|
||||
debug_geometry_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void DEBUG_TURNS_START(const std::string & debug_turns_path)
|
||||
{
|
||||
dg_output_turn_debug = debug_turns_path != "";
|
||||
if (dg_output_turn_debug)
|
||||
{
|
||||
dg_debug_turns_file.open(debug_turns_path);
|
||||
dg_debug_turns_file << "{\"type\":\"FeatureCollection\", \"features\":[" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DEBUG_SIGNAL(
|
||||
const NodeID node,
|
||||
const std::vector<QueryNode>& m_node_info_list,
|
||||
const int traffic_signal_penalty)
|
||||
{
|
||||
if (dg_output_turn_debug)
|
||||
{
|
||||
const QueryNode &nodeinfo = m_node_info_list[node];
|
||||
if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
|
||||
dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"trafficlights\",\"cost\":" << traffic_signal_penalty/10. << "},";
|
||||
dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << nodeinfo.lon/COORDINATE_PRECISION << "," << nodeinfo.lat/COORDINATE_PRECISION << "]}}";
|
||||
dg_first_turn_debug = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DEBUG_UTURN(
|
||||
const NodeID node,
|
||||
const std::vector<QueryNode>& m_node_info_list,
|
||||
const int traffic_signal_penalty)
|
||||
{
|
||||
if (dg_output_turn_debug)
|
||||
{
|
||||
const QueryNode &nodeinfo = m_node_info_list[node];
|
||||
if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
|
||||
dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"trafficlights\",\"cost\":" << traffic_signal_penalty/10. << "},";
|
||||
dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << nodeinfo.lon/COORDINATE_PRECISION << "," << nodeinfo.lat/COORDINATE_PRECISION << "]}}";
|
||||
dg_first_turn_debug = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void DEBUG_TURN(
|
||||
const NodeID node,
|
||||
const std::vector<QueryNode>& m_node_info_list,
|
||||
const FixedPointCoordinate & first_coordinate,
|
||||
const int turn_angle,
|
||||
const int turn_penalty)
|
||||
{
|
||||
if (turn_penalty > 0 && dg_output_turn_debug)
|
||||
{
|
||||
const QueryNode &v = m_node_info_list[node];
|
||||
|
||||
const float bearing_uv = coordinate_calculation::bearing(first_coordinate,v);
|
||||
float uvw_normal = bearing_uv + turn_angle/2;
|
||||
while (uvw_normal >= 360.) { uvw_normal -= 360.; }
|
||||
|
||||
if (!dg_first_turn_debug) dg_debug_turns_file << "," << std::endl;
|
||||
dg_debug_turns_file << "{ \"type\":\"Feature\",\"properties\":{\"type\":\"turn\",\"cost\":" << turn_penalty/10. << ",\"turn_angle\":" << static_cast<int>(turn_angle) << ",\"normal\":" << static_cast<int>(uvw_normal) << "},";
|
||||
dg_debug_turns_file << " \"geometry\":{\"type\":\"Point\",\"coordinates\":[" << std::setprecision(12) << v.lon/COORDINATE_PRECISION << "," << v.lat/COORDINATE_PRECISION << "]}}";
|
||||
dg_first_turn_debug = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void DEBUG_TURNS_STOP()
|
||||
{
|
||||
if (dg_output_turn_debug)
|
||||
{
|
||||
dg_debug_turns_file << std::endl << "]}" << std::endl;
|
||||
dg_debug_turns_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG_GEOMETRY
|
||||
|
||||
|
||||
#endif // DEBUG_GEOMETRY_H
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DIST_TABLE_WRAPPER_H
|
||||
#define DIST_TABLE_WRAPPER_H
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <boost/assert.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
// This Wrapper provides an easier access to a distance table that is given as an linear vector
|
||||
|
||||
template <typename T> class DistTableWrapper
|
||||
{
|
||||
public:
|
||||
using Iterator = typename std::vector<T>::iterator;
|
||||
using ConstIterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
DistTableWrapper(std::vector<T> table, std::size_t number_of_nodes)
|
||||
: table_(std::move(table)), number_of_nodes_(number_of_nodes)
|
||||
{
|
||||
BOOST_ASSERT_MSG(table.size() == 0, "table is empty");
|
||||
BOOST_ASSERT_MSG(number_of_nodes_ * number_of_nodes_ <= table_.size(),
|
||||
"number_of_nodes_ is invalid");
|
||||
};
|
||||
|
||||
std::size_t GetNumberOfNodes() const { return number_of_nodes_; }
|
||||
|
||||
std::size_t size() const { return table_.size(); }
|
||||
|
||||
EdgeWeight operator()(NodeID from, NodeID to) const
|
||||
{
|
||||
BOOST_ASSERT_MSG(from < number_of_nodes_, "from ID is out of bound");
|
||||
BOOST_ASSERT_MSG(to < number_of_nodes_, "to ID is out of bound");
|
||||
|
||||
const auto index = from * number_of_nodes_ + to;
|
||||
|
||||
BOOST_ASSERT_MSG(index < table_.size(), "index is out of bound");
|
||||
|
||||
return table_[index];
|
||||
}
|
||||
|
||||
ConstIterator begin() const { return std::begin(table_); }
|
||||
|
||||
Iterator begin() { return std::begin(table_); }
|
||||
|
||||
ConstIterator end() const { return std::end(table_); }
|
||||
|
||||
Iterator end() { return std::end(table_); }
|
||||
|
||||
NodeID GetIndexOfMaxValue() const
|
||||
{
|
||||
return std::distance(table_.begin(), std::max_element(table_.begin(), table_.end()));
|
||||
}
|
||||
|
||||
std::vector<T> GetTable() const { return table_; }
|
||||
|
||||
private:
|
||||
std::vector<T> table_;
|
||||
const std::size_t number_of_nodes_;
|
||||
};
|
||||
|
||||
#endif // DIST_TABLE_WRAPPER_H
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNAMICGRAPH_HPP
|
||||
#define DYNAMICGRAPH_HPP
|
||||
|
||||
#include "deallocating_vector.hpp"
|
||||
#include "../util/integer_range.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
template <typename EdgeDataT> class DynamicGraph
|
||||
{
|
||||
public:
|
||||
using EdgeData = EdgeDataT;
|
||||
using NodeIterator = unsigned;
|
||||
using EdgeIterator = unsigned;
|
||||
using EdgeRange = osrm::range<EdgeIterator>;
|
||||
|
||||
class InputEdge
|
||||
{
|
||||
public:
|
||||
NodeIterator source;
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
|
||||
InputEdge()
|
||||
: source(std::numeric_limits<NodeIterator>::max()),
|
||||
target(std::numeric_limits<NodeIterator>::max())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
InputEdge(NodeIterator source, NodeIterator target, Ts &&... data)
|
||||
: source(source), target(target), data(std::forward<Ts>(data)...)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const InputEdge &rhs) const
|
||||
{
|
||||
return std::tie(source, target) < std::tie(rhs.source, rhs.target);
|
||||
}
|
||||
};
|
||||
|
||||
// Constructs an empty graph with a given number of nodes.
|
||||
explicit DynamicGraph(NodeIterator nodes) : number_of_nodes(nodes), number_of_edges(0)
|
||||
{
|
||||
node_array.reserve(number_of_nodes);
|
||||
node_array.resize(number_of_nodes);
|
||||
|
||||
edge_list.reserve(number_of_nodes * 1.1);
|
||||
edge_list.resize(number_of_nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a DynamicGraph from a list of edges sorted by source node id.
|
||||
*/
|
||||
template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
|
||||
{
|
||||
// we need to cast here because DeallocatingVector does not have a valid const iterator
|
||||
BOOST_ASSERT(std::is_sorted(const_cast<ContainerT&>(graph).begin(), const_cast<ContainerT&>(graph).end()));
|
||||
|
||||
number_of_nodes = nodes;
|
||||
number_of_edges = static_cast<EdgeIterator>(graph.size());
|
||||
node_array.resize(number_of_nodes + 1);
|
||||
EdgeIterator edge = 0;
|
||||
EdgeIterator position = 0;
|
||||
for (const auto node : osrm::irange(0u, number_of_nodes))
|
||||
{
|
||||
EdgeIterator last_edge = edge;
|
||||
while (edge < number_of_edges && graph[edge].source == node)
|
||||
{
|
||||
++edge;
|
||||
}
|
||||
node_array[node].first_edge = position;
|
||||
node_array[node].edges = edge - last_edge;
|
||||
position += node_array[node].edges;
|
||||
}
|
||||
node_array.back().first_edge = position;
|
||||
edge_list.reserve(static_cast<std::size_t>(edge_list.size() * 1.1));
|
||||
edge_list.resize(position);
|
||||
edge = 0;
|
||||
for (const auto node : osrm::irange(0u, number_of_nodes))
|
||||
{
|
||||
for (const auto i : osrm::irange(node_array[node].first_edge,
|
||||
node_array[node].first_edge + node_array[node].edges))
|
||||
{
|
||||
edge_list[i].target = graph[edge].target;
|
||||
BOOST_ASSERT(edge_list[i].target < number_of_nodes);
|
||||
edge_list[i].data = graph[edge].data;
|
||||
++edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~DynamicGraph() {}
|
||||
|
||||
unsigned GetNumberOfNodes() const { return number_of_nodes; }
|
||||
|
||||
unsigned GetNumberOfEdges() const { return number_of_edges; }
|
||||
|
||||
unsigned GetOutDegree(const NodeIterator n) const { return node_array[n].edges; }
|
||||
|
||||
unsigned GetDirectedOutDegree(const NodeIterator n) const
|
||||
{
|
||||
unsigned degree = 0;
|
||||
for (const auto edge : osrm::irange(BeginEdges(n), EndEdges(n)))
|
||||
{
|
||||
if (!GetEdgeData(edge).reversed)
|
||||
{
|
||||
++degree;
|
||||
}
|
||||
}
|
||||
return degree;
|
||||
}
|
||||
|
||||
NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(edge_list[e].target); }
|
||||
|
||||
void SetTarget(const EdgeIterator e, const NodeIterator n) { edge_list[e].target = n; }
|
||||
|
||||
EdgeDataT &GetEdgeData(const EdgeIterator e) { return edge_list[e].data; }
|
||||
|
||||
const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return edge_list[e].data; }
|
||||
|
||||
EdgeIterator BeginEdges(const NodeIterator n) const
|
||||
{
|
||||
return EdgeIterator(node_array[n].first_edge);
|
||||
}
|
||||
|
||||
EdgeIterator EndEdges(const NodeIterator n) const
|
||||
{
|
||||
return EdgeIterator(node_array[n].first_edge + node_array[n].edges);
|
||||
}
|
||||
|
||||
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
|
||||
{
|
||||
return osrm::irange(BeginEdges(node), EndEdges(node));
|
||||
}
|
||||
|
||||
NodeIterator InsertNode()
|
||||
{
|
||||
node_array.emplace_back(node_array.back());
|
||||
number_of_nodes += 1;
|
||||
|
||||
return number_of_nodes;
|
||||
}
|
||||
|
||||
// adds an edge. Invalidates edge iterators for the source node
|
||||
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
|
||||
{
|
||||
Node &node = node_array[from];
|
||||
EdgeIterator newFirstEdge = node.edges + node.first_edge;
|
||||
if (newFirstEdge >= edge_list.size() || !isDummy(newFirstEdge))
|
||||
{
|
||||
if (node.first_edge != 0 && isDummy(node.first_edge - 1))
|
||||
{
|
||||
node.first_edge--;
|
||||
edge_list[node.first_edge] = edge_list[node.first_edge + node.edges];
|
||||
}
|
||||
else
|
||||
{
|
||||
EdgeIterator newFirstEdge = (EdgeIterator)edge_list.size();
|
||||
unsigned newSize = node.edges * 1.1 + 2;
|
||||
EdgeIterator requiredCapacity = newSize + edge_list.size();
|
||||
EdgeIterator oldCapacity = edge_list.capacity();
|
||||
if (requiredCapacity >= oldCapacity)
|
||||
{
|
||||
edge_list.reserve(requiredCapacity * 1.1);
|
||||
}
|
||||
edge_list.resize(edge_list.size() + newSize);
|
||||
for (const auto i : osrm::irange(0u, node.edges))
|
||||
{
|
||||
edge_list[newFirstEdge + i] = edge_list[node.first_edge + i];
|
||||
makeDummy(node.first_edge + i);
|
||||
}
|
||||
for (const auto i : osrm::irange(node.edges + 1, newSize))
|
||||
{
|
||||
makeDummy(newFirstEdge + i);
|
||||
}
|
||||
node.first_edge = newFirstEdge;
|
||||
}
|
||||
}
|
||||
Edge &edge = edge_list[node.first_edge + node.edges];
|
||||
edge.target = to;
|
||||
edge.data = data;
|
||||
++number_of_edges;
|
||||
++node.edges;
|
||||
return EdgeIterator(node.first_edge + node.edges);
|
||||
}
|
||||
|
||||
// removes an edge. Invalidates edge iterators for the source node
|
||||
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
|
||||
{
|
||||
Node &node = node_array[source];
|
||||
--number_of_edges;
|
||||
--node.edges;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
|
||||
const unsigned last = node.first_edge + node.edges;
|
||||
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
|
||||
// swap with last edge
|
||||
edge_list[e] = edge_list[last];
|
||||
makeDummy(last);
|
||||
}
|
||||
|
||||
// removes all edges (source,target)
|
||||
int32_t DeleteEdgesTo(const NodeIterator source, const NodeIterator target)
|
||||
{
|
||||
int32_t deleted = 0;
|
||||
for (EdgeIterator i = BeginEdges(source), iend = EndEdges(source); i < iend - deleted; ++i)
|
||||
{
|
||||
if (edge_list[i].target == target)
|
||||
{
|
||||
do
|
||||
{
|
||||
deleted++;
|
||||
edge_list[i] = edge_list[iend - deleted];
|
||||
makeDummy(iend - deleted);
|
||||
} while (i < iend - deleted && edge_list[i].target == target);
|
||||
}
|
||||
}
|
||||
|
||||
number_of_edges -= deleted;
|
||||
node_array[source].edges -= deleted;
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
|
||||
{
|
||||
for (const auto i : osrm::irange(BeginEdges(from), EndEdges(from)))
|
||||
{
|
||||
if (to == edge_list[i].target)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return SPECIAL_EDGEID;
|
||||
}
|
||||
|
||||
// searches for a specific edge
|
||||
EdgeIterator FindSmallestEdge(const NodeIterator from, const NodeIterator to) const
|
||||
{
|
||||
EdgeIterator smallest_edge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
|
||||
for (auto edge : GetAdjacentEdgeRange(from))
|
||||
{
|
||||
const NodeID target = GetTarget(edge);
|
||||
const EdgeWeight weight = GetEdgeData(edge).distance;
|
||||
if (target == to && weight < smallest_weight)
|
||||
{
|
||||
smallest_edge = edge;
|
||||
smallest_weight = weight;
|
||||
}
|
||||
}
|
||||
return smallest_edge;
|
||||
}
|
||||
|
||||
EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
|
||||
{
|
||||
EdgeIterator tmp = FindEdge(from, to);
|
||||
return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
|
||||
}
|
||||
|
||||
EdgeIterator
|
||||
FindEdgeIndicateIfReverse(const NodeIterator from, const NodeIterator to, bool &result) const
|
||||
{
|
||||
EdgeIterator current_iterator = FindEdge(from, to);
|
||||
if (SPECIAL_NODEID == current_iterator)
|
||||
{
|
||||
current_iterator = FindEdge(to, from);
|
||||
if (SPECIAL_NODEID != current_iterator)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return current_iterator;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isDummy(const EdgeIterator edge) const
|
||||
{
|
||||
return edge_list[edge].target == (std::numeric_limits<NodeIterator>::max)();
|
||||
}
|
||||
|
||||
void makeDummy(const EdgeIterator edge)
|
||||
{
|
||||
edge_list[edge].target = (std::numeric_limits<NodeIterator>::max)();
|
||||
}
|
||||
|
||||
struct Node
|
||||
{
|
||||
// index of the first edge
|
||||
EdgeIterator first_edge;
|
||||
// amount of edges
|
||||
unsigned edges;
|
||||
};
|
||||
|
||||
struct Edge
|
||||
{
|
||||
NodeIterator target;
|
||||
EdgeDataT data;
|
||||
};
|
||||
|
||||
NodeIterator number_of_nodes;
|
||||
std::atomic_uint number_of_edges;
|
||||
|
||||
std::vector<Node> node_array;
|
||||
DeallocatingVector<Edge> edge_list;
|
||||
};
|
||||
|
||||
#endif // DYNAMICGRAPH_HPP
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FINGERPRINT_H
|
||||
#define FINGERPRINT_H
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
// implements a singleton, i.e. there is one and only one conviguration object
|
||||
class FingerPrint
|
||||
{
|
||||
public:
|
||||
static FingerPrint GetValid();
|
||||
const boost::uuids::uuid &GetFingerPrint() const;
|
||||
bool IsMagicNumberOK(const FingerPrint &other) const;
|
||||
bool TestGraphUtil(const FingerPrint &other) const;
|
||||
bool TestPrepare(const FingerPrint &other) const;
|
||||
bool TestRTree(const FingerPrint &other) const;
|
||||
bool TestQueryObjects(const FingerPrint &other) const;
|
||||
|
||||
private:
|
||||
unsigned magic_number;
|
||||
char md5_prepare[33];
|
||||
char md5_tree[33];
|
||||
char md5_graph[33];
|
||||
char md5_objects[33];
|
||||
|
||||
// initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
|
||||
boost::uuids::uuid named_uuid;
|
||||
|
||||
};
|
||||
|
||||
static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
|
||||
|
||||
|
||||
#endif /* FingerPrint_H */
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#include "util/osrm_exception.hpp"
|
||||
|
||||
#include <boost/uuid/name_generator.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#cmakedefine MD5PREPARE "${MD5PREPARE}"
|
||||
#cmakedefine MD5RTREE "${MD5RTREE}"
|
||||
#cmakedefine MD5GRAPH "${MD5GRAPH}"
|
||||
#cmakedefine MD5OBJECTS "${MD5OBJECTS}"
|
||||
|
||||
FingerPrint FingerPrint::GetValid()
|
||||
{
|
||||
FingerPrint fingerprint;
|
||||
|
||||
fingerprint.magic_number = 1297240911;
|
||||
fingerprint.md5_prepare[32] = fingerprint.md5_tree[32] = fingerprint.md5_graph[32] = fingerprint.md5_objects[32] = '\0';
|
||||
|
||||
// 6ba7b810-9dad-11d1-80b4-00c04fd430c8 is a Well Known UUID representing the DNS
|
||||
// namespace. Its use here indicates that we own this part of the UUID space
|
||||
// in the DNS realm. *Usually*, we would then generate a UUID based on "something.project-osrm.org",
|
||||
// but this whole class is a hack. Anyway, named_uuid needs to be initialized to something
|
||||
// before it can be used, and this is as good as anything else for these purposes.
|
||||
fingerprint.named_uuid = boost::uuids::string_generator()( "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}");
|
||||
|
||||
boost::uuids::name_generator gen(fingerprint.named_uuid);
|
||||
std::string temp_string;
|
||||
|
||||
std::memcpy(fingerprint.md5_prepare, MD5PREPARE, 32);
|
||||
temp_string += fingerprint.md5_prepare;
|
||||
std::memcpy(fingerprint.md5_tree, MD5RTREE, 32);
|
||||
temp_string += fingerprint.md5_tree;
|
||||
std::memcpy(fingerprint.md5_graph, MD5GRAPH, 32);
|
||||
temp_string += fingerprint.md5_graph;
|
||||
std::memcpy(fingerprint.md5_objects, MD5OBJECTS, 32);
|
||||
temp_string += fingerprint.md5_objects;
|
||||
|
||||
fingerprint.named_uuid = gen(temp_string);
|
||||
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
const boost::uuids::uuid &FingerPrint::GetFingerPrint() const { return named_uuid; }
|
||||
|
||||
bool FingerPrint::IsMagicNumberOK(const FingerPrint& other) const { return other.magic_number == magic_number; }
|
||||
|
||||
bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_graph, md5_graph + 32, other.md5_graph);
|
||||
}
|
||||
|
||||
bool FingerPrint::TestPrepare(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_prepare, md5_prepare + 32, other.md5_prepare);
|
||||
}
|
||||
|
||||
bool FingerPrint::TestRTree(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_tree, md5_tree + 32, other.md5_tree);
|
||||
}
|
||||
|
||||
bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
|
||||
{
|
||||
if (!IsMagicNumberOK(other))
|
||||
{
|
||||
throw osrm::exception("missing magic number. Check or reprocess the file");
|
||||
}
|
||||
return std::equal(md5_objects, md5_objects + 32, other.md5_objects);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIXED_POINT_NUMBER_HPP
|
||||
#define FIXED_POINT_NUMBER_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
// implements an binary based fixed point number type
|
||||
template <unsigned FractionalBitSize,
|
||||
bool use_64_bits = false,
|
||||
bool is_unsigned = false,
|
||||
bool truncate_results = false>
|
||||
class FixedPointNumber
|
||||
{
|
||||
static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0");
|
||||
static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32");
|
||||
|
||||
typename std::conditional<use_64_bits, int64_t, int32_t>::type m_fixed_point_state;
|
||||
constexpr static const decltype(m_fixed_point_state) PRECISION = 1 << FractionalBitSize;
|
||||
|
||||
// state signage encapsulates whether the state should either represent a
|
||||
// signed or an unsigned floating point number
|
||||
using state_signage =
|
||||
typename std::conditional<is_unsigned,
|
||||
typename std::make_unsigned<decltype(m_fixed_point_state)>::type,
|
||||
decltype(m_fixed_point_state)>::type;
|
||||
|
||||
public:
|
||||
FixedPointNumber() : m_fixed_point_state(0) {}
|
||||
|
||||
// the type is either initialized with a floating point value or an
|
||||
// integral state. Anything else will throw at compile-time.
|
||||
template <class T>
|
||||
constexpr FixedPointNumber(const T &&input) noexcept
|
||||
: m_fixed_point_state(static_cast<decltype(m_fixed_point_state)>(
|
||||
std::round(std::forward<const T>(input) * PRECISION)))
|
||||
{
|
||||
static_assert(
|
||||
std::is_floating_point<T>::value || std::is_integral<T>::value,
|
||||
"FixedPointNumber needs to be initialized with floating point or integral value");
|
||||
}
|
||||
|
||||
// get max value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
constexpr static auto max() noexcept -> T
|
||||
{
|
||||
return static_cast<T>(std::numeric_limits<state_signage>::max()) / PRECISION;
|
||||
}
|
||||
|
||||
// get min value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
constexpr static auto min() noexcept -> T
|
||||
{
|
||||
return static_cast<T>(1) / PRECISION;
|
||||
}
|
||||
|
||||
// get lowest value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
constexpr static auto lowest() noexcept -> T
|
||||
{
|
||||
return static_cast<T>(std::numeric_limits<state_signage>::min()) / PRECISION;
|
||||
}
|
||||
|
||||
// cast to floating point type T, return value
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
explicit operator const T() const noexcept
|
||||
{
|
||||
// casts to external type (signed or unsigned) and then to float
|
||||
return static_cast<T>(static_cast<state_signage>(m_fixed_point_state)) / PRECISION;
|
||||
}
|
||||
|
||||
// warn about cast to integral type T, its disabled for good reason
|
||||
template <typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
|
||||
explicit operator T() const
|
||||
{
|
||||
static_assert(std::is_integral<T>::value,
|
||||
"casts to integral types have been disabled on purpose");
|
||||
}
|
||||
|
||||
// compare, ie. sort fixed-point numbers
|
||||
bool operator<(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
return m_fixed_point_state < other.m_fixed_point_state;
|
||||
}
|
||||
|
||||
// equality, ie. sort fixed-point numbers
|
||||
bool operator==(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
return m_fixed_point_state == other.m_fixed_point_state;
|
||||
}
|
||||
|
||||
bool operator!=(const FixedPointNumber &other) const { return !(*this == other); }
|
||||
bool operator>(const FixedPointNumber &other) const { return other < *this; }
|
||||
bool operator<=(const FixedPointNumber &other) const { return !(other < *this); }
|
||||
bool operator>=(const FixedPointNumber &other) const { return !(*this < other); }
|
||||
|
||||
// arithmetic operators
|
||||
FixedPointNumber operator+(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
FixedPointNumber tmp = *this;
|
||||
tmp.m_fixed_point_state += other.m_fixed_point_state;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
this->m_fixed_point_state += other.m_fixed_point_state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedPointNumber operator-(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
FixedPointNumber tmp = *this;
|
||||
tmp.m_fixed_point_state -= other.m_fixed_point_state;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
this->m_fixed_point_state -= other.m_fixed_point_state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedPointNumber operator*(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp *= other.m_fixed_point_state;
|
||||
|
||||
// rounding!
|
||||
if (!truncate_results)
|
||||
{
|
||||
temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
|
||||
}
|
||||
temp >>= FractionalBitSize;
|
||||
FixedPointNumber tmp;
|
||||
tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp *= other.m_fixed_point_state;
|
||||
|
||||
// rounding!
|
||||
if (!truncate_results)
|
||||
{
|
||||
temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1);
|
||||
}
|
||||
temp >>= FractionalBitSize;
|
||||
this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedPointNumber operator/(const FixedPointNumber &other) const noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp <<= FractionalBitSize;
|
||||
temp /= static_cast<int64_t>(other.m_fixed_point_state);
|
||||
FixedPointNumber tmp;
|
||||
tmp.m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept
|
||||
{
|
||||
int64_t temp = this->m_fixed_point_state;
|
||||
temp <<= FractionalBitSize;
|
||||
temp /= static_cast<int64_t>(other.m_fixed_point_state);
|
||||
FixedPointNumber tmp;
|
||||
this->m_fixed_point_state = static_cast<decltype(m_fixed_point_state)>(temp);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4");
|
||||
}
|
||||
#endif // FIXED_POINT_NUMBER_HPP
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (c) 2013, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FLOATING_POINT_HPP
|
||||
#define FLOATING_POINT_HPP
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
template <typename FloatT> bool epsilon_compare(const FloatT number1, const FloatT number2)
|
||||
{
|
||||
static_assert(std::is_floating_point<FloatT>::value, "type must be floating point");
|
||||
return (std::abs(number1 - number2) < std::numeric_limits<FloatT>::epsilon());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FLOATING_POINT_HPP
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Project OSRM contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GRAPH_LOADER_HPP
|
||||
#define GRAPH_LOADER_HPP
|
||||
|
||||
#include "fingerprint.hpp"
|
||||
#include "osrm_exception.hpp"
|
||||
#include "simple_logger.hpp"
|
||||
#include "../data_structures/external_memory_node.hpp"
|
||||
#include "../data_structures/import_edge.hpp"
|
||||
#include "../data_structures/query_node.hpp"
|
||||
#include "../data_structures/restriction.hpp"
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Reads the .restrictions file and loads it to a vector.
|
||||
* The since the restrictions reference nodes using their external node id,
|
||||
* we need to renumber it to the new internal id.
|
||||
*/
|
||||
unsigned loadRestrictionsFromFile(std::istream &input_stream,
|
||||
std::vector<TurnRestriction> &restriction_list)
|
||||
{
|
||||
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
|
||||
FingerPrint fingerprint_loaded;
|
||||
unsigned number_of_usable_restrictions = 0;
|
||||
input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
|
||||
if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
input_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
|
||||
restriction_list.resize(number_of_usable_restrictions);
|
||||
if (number_of_usable_restrictions > 0)
|
||||
{
|
||||
input_stream.read((char *)restriction_list.data(),
|
||||
number_of_usable_restrictions * sizeof(TurnRestriction));
|
||||
}
|
||||
|
||||
return number_of_usable_restrictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the beginning of an .osrm file and produces:
|
||||
* - list of barrier nodes
|
||||
* - list of traffic lights
|
||||
* - nodes indexed by their internal (non-osm) id
|
||||
*/
|
||||
NodeID loadNodesFromFile(std::istream &input_stream,
|
||||
std::vector<NodeID> &barrier_node_list,
|
||||
std::vector<NodeID> &traffic_light_node_list,
|
||||
std::vector<QueryNode> &node_array)
|
||||
{
|
||||
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
|
||||
FingerPrint fingerprint_loaded;
|
||||
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
|
||||
|
||||
if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
NodeID n;
|
||||
input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
|
||||
SimpleLogger().Write() << "Importing n = " << n << " nodes ";
|
||||
|
||||
ExternalMemoryNode current_node;
|
||||
for (NodeID i = 0; i < n; ++i)
|
||||
{
|
||||
input_stream.read(reinterpret_cast<char *>(¤t_node), sizeof(ExternalMemoryNode));
|
||||
node_array.emplace_back(current_node.lat, current_node.lon, current_node.node_id);
|
||||
if (current_node.barrier)
|
||||
{
|
||||
barrier_node_list.emplace_back(i);
|
||||
}
|
||||
if (current_node.traffic_lights)
|
||||
{
|
||||
traffic_light_node_list.emplace_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
// tighten vector sizes
|
||||
barrier_node_list.shrink_to_fit();
|
||||
traffic_light_node_list.shrink_to_fit();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a .osrm file and produces the edges.
|
||||
*/
|
||||
NodeID loadEdgesFromFile(std::istream &input_stream, std::vector<NodeBasedEdge> &edge_list)
|
||||
{
|
||||
EdgeID m;
|
||||
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
|
||||
edge_list.resize(m);
|
||||
SimpleLogger().Write() << " and " << m << " edges ";
|
||||
|
||||
input_stream.read((char *)edge_list.data(), m * sizeof(NodeBasedEdge));
|
||||
|
||||
BOOST_ASSERT(edge_list.size() > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
SimpleLogger().Write() << "Validating loaded edges...";
|
||||
tbb::parallel_sort(edge_list.begin(), edge_list.end(),
|
||||
[](const NodeBasedEdge &lhs, const NodeBasedEdge &rhs)
|
||||
{
|
||||
return (lhs.source < rhs.source) ||
|
||||
(lhs.source == rhs.source && lhs.target < rhs.target);
|
||||
});
|
||||
for (auto i = 1u; i < edge_list.size(); ++i)
|
||||
{
|
||||
const auto &edge = edge_list[i];
|
||||
const auto &prev_edge = edge_list[i - 1];
|
||||
|
||||
BOOST_ASSERT_MSG(edge.weight > 0, "loaded null weight");
|
||||
BOOST_ASSERT_MSG(edge.forward, "edge must be oriented in forward direction");
|
||||
BOOST_ASSERT_MSG(edge.travel_mode != TRAVEL_MODE_INACCESSIBLE, "loaded non-accessible");
|
||||
|
||||
BOOST_ASSERT_MSG(edge.source != edge.target, "loaded edges contain a loop");
|
||||
BOOST_ASSERT_MSG(edge.source != prev_edge.source || edge.target != prev_edge.target,
|
||||
"loaded edges contain a multi edge");
|
||||
}
|
||||
#endif
|
||||
|
||||
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
template <typename NodeT, typename EdgeT>
|
||||
unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
|
||||
std::vector<NodeT> &node_list,
|
||||
std::vector<EdgeT> &edge_list,
|
||||
unsigned *check_sum)
|
||||
{
|
||||
if (!boost::filesystem::exists(hsgr_file))
|
||||
{
|
||||
throw osrm::exception("hsgr file does not exist");
|
||||
}
|
||||
if (0 == boost::filesystem::file_size(hsgr_file))
|
||||
{
|
||||
throw osrm::exception("hsgr file is empty");
|
||||
}
|
||||
|
||||
boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
|
||||
|
||||
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
|
||||
FingerPrint fingerprint_loaded;
|
||||
hsgr_input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
|
||||
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
|
||||
"Reprocess to get rid of this warning.";
|
||||
}
|
||||
|
||||
unsigned number_of_nodes = 0;
|
||||
unsigned number_of_edges = 0;
|
||||
hsgr_input_stream.read(reinterpret_cast<char *>(check_sum), sizeof(unsigned));
|
||||
hsgr_input_stream.read(reinterpret_cast<char *>(&number_of_nodes), sizeof(unsigned));
|
||||
BOOST_ASSERT_MSG(0 != number_of_nodes, "number of nodes is zero");
|
||||
hsgr_input_stream.read(reinterpret_cast<char *>(&number_of_edges), sizeof(unsigned));
|
||||
|
||||
SimpleLogger().Write() << "number_of_nodes: " << number_of_nodes
|
||||
<< ", number_of_edges: " << number_of_edges;
|
||||
|
||||
// BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
|
||||
node_list.resize(number_of_nodes);
|
||||
hsgr_input_stream.read(reinterpret_cast<char *>(&node_list[0]),
|
||||
number_of_nodes * sizeof(NodeT));
|
||||
|
||||
edge_list.resize(number_of_edges);
|
||||
if (number_of_edges > 0)
|
||||
{
|
||||
hsgr_input_stream.read(reinterpret_cast<char *>(&edge_list[0]),
|
||||
number_of_edges * sizeof(EdgeT));
|
||||
}
|
||||
hsgr_input_stream.close();
|
||||
|
||||
return number_of_nodes;
|
||||
}
|
||||
|
||||
#endif // GRAPH_LOADER_HPP
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef GRAPH_UTILS_HPP
|
||||
#define GRAPH_UTILS_HPP
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <vector>
|
||||
|
||||
/// This function checks if the graph (consisting of directed edges) is undirected
|
||||
template<typename GraphT>
|
||||
bool isUndirectedGraph(const GraphT& graph)
|
||||
{
|
||||
for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source)
|
||||
{
|
||||
for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge)
|
||||
{
|
||||
const auto& data = graph.GetEdgeData(edge);
|
||||
|
||||
auto target = graph.GetTarget(edge);
|
||||
BOOST_ASSERT(target != SPECIAL_NODEID);
|
||||
|
||||
bool found_reverse = false;
|
||||
for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge)
|
||||
{
|
||||
auto rev_target = graph.GetTarget(rev_edge);
|
||||
BOOST_ASSERT(rev_target != SPECIAL_NODEID);
|
||||
|
||||
if (rev_target != source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BOOST_ASSERT_MSG(!found_reverse, "Found more than one reverse edge");
|
||||
found_reverse = true;
|
||||
}
|
||||
|
||||
if (!found_reverse)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// Since DynamicGraph assumes directed edges we have to make sure we transformed
|
||||
/// the compressed edge format into single directed edges. We do this to make sure
|
||||
/// every node also knows its incoming edges, not only its outgoing edges and use the reversed=true
|
||||
/// flag to indicate which is which.
|
||||
///
|
||||
/// We do the transformation in the following way:
|
||||
///
|
||||
/// if the edge (a, b) is split:
|
||||
/// 1. this edge must be in only one direction, so its a --> b
|
||||
/// 2. there must be another directed edge b --> a somewhere in the data
|
||||
/// if the edge (a, b) is not split:
|
||||
/// 1. this edge be on of a --> b od a <-> b
|
||||
/// (a <-- b gets reducted to b --> a)
|
||||
/// 2. a --> b will be transformed to a --> b and b <-- a
|
||||
/// 3. a <-> b will be transformed to a --> b and b --> a
|
||||
template<typename OutputEdgeT, typename InputEdgeT, typename FunctorT>
|
||||
std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdgeT>& input_edge_list, FunctorT copy_data)
|
||||
{
|
||||
std::vector<OutputEdgeT> output_edge_list;
|
||||
|
||||
OutputEdgeT edge;
|
||||
for (const auto& input_edge : input_edge_list)
|
||||
{
|
||||
// edges that are not forward get converted by flipping the end points
|
||||
BOOST_ASSERT(input_edge.forward);
|
||||
|
||||
edge.source = input_edge.source;
|
||||
edge.target = input_edge.target;
|
||||
edge.data.reversed = false;
|
||||
|
||||
BOOST_ASSERT(edge.source != edge.target);
|
||||
|
||||
copy_data(edge, input_edge);
|
||||
|
||||
output_edge_list.push_back(edge);
|
||||
|
||||
if (!input_edge.is_split)
|
||||
{
|
||||
std::swap(edge.source, edge.target);
|
||||
edge.data.reversed = !input_edge.backward;
|
||||
output_edge_list.push_back(edge);
|
||||
}
|
||||
}
|
||||
|
||||
return output_edge_list;
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user