Skip to content

Commit

Permalink
Merge pull request #4942 from mpimenov/traffic-python-bindings
Browse files Browse the repository at this point in the history
[traffic] Added python bindings for traffic serialization.
  • Loading branch information
ygorshenin authored Dec 9, 2016
2 parents 2eef321 + c2918c0 commit ce69596
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 19 deletions.
22 changes: 22 additions & 0 deletions pyhelpers/vector_list_conversion.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "std/vector.hpp"

#include <boost/python.hpp>

namespace
{
template <typename T>
vector<T> python_list_to_std_vector(boost::python::object const & iterable)
{
return vector<T>(boost::python::stl_input_iterator<T>(iterable),
boost::python::stl_input_iterator<T>());
}

template <typename T>
boost::python::list std_vector_to_python_list(vector<T> const & v)
{
boost::python::object get_iter = boost::python::iterator<vector<T>>();
return boost::python::list(get_iter(v));
}
} // namespace
15 changes: 13 additions & 2 deletions traffic/pytraffic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,23 @@ endif()

omim_link_libraries(
${PROJECT_NAME}
${PYTHON_LIBRARIES}
${Boost_LIBRARIES}
editor
routing
indexer
traffic
platform
geometry
coding
base
stats_client
jansson
oauthcpp
protobuf
pugixml
opening_hours
${PYTHON_LIBRARIES}
${Boost_LIBRARIES}
${LIBZ}
)

set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
145 changes: 130 additions & 15 deletions traffic/pytraffic/bindings.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,147 @@
#include "traffic/traffic_info.hpp"
#include "traffic/speed_groups.hpp"

#include "indexer/classificator_loader.hpp"

#include "platform/platform.hpp"

#include "base/assert.hpp"
#include "base/logging.hpp"
#include "base/math.hpp"

#include "std/cstdint.hpp"
#include "std/map.hpp"
#include "std/sstream.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"

#include "pyhelpers/vector_list_conversion.hpp"
#include "pyhelpers/vector_uint8.hpp"

#include <boost/python.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

namespace
{
using namespace boost::python;

vector<uint8_t> Serialize(traffic::TrafficInfo::Coloring const & coloring)
struct SegmentSpeeds
{
SegmentSpeeds() = default;
SegmentSpeeds(double weightedSpeed, double weightedRefSpeed, double weight)
: m_weightedSpeed(weightedSpeed), m_weightedRefSpeed(weightedRefSpeed), m_weight(weight)
{
}

double m_weightedSpeed = 0;
double m_weightedRefSpeed = 0;
double m_weight = 0;
};

using SegmentMapping = map<traffic::TrafficInfo::RoadSegmentId, SegmentSpeeds>;

string SegmentSpeedsRepr(SegmentSpeeds const & v)
{
vector<uint8_t> data;
traffic::TrafficInfo::SerializeTrafficData(coloring, data);
return data;
ostringstream ss;
ss << "SegmentSpeeds("
<< " weighted_speed=" << v.m_weightedSpeed << " weighted_ref_speed=" << v.m_weightedRefSpeed
<< " weight=" << v.m_weight << " )";
return ss.str();
}

traffic::TrafficInfo::Coloring Deserialize(vector<uint8_t> const & data)
traffic::TrafficInfo::Coloring TransformToSpeedGroups(SegmentMapping const & segmentMapping)
{
traffic::TrafficInfo::Coloring coloring;
traffic::TrafficInfo::DeserializeTrafficData(data, coloring);
return coloring;
double const kEps = 1e-9;
traffic::TrafficInfo::Coloring result;
for (auto const & kv : segmentMapping)
{
double const ws = kv.second.m_weightedSpeed;
double const wrs = kv.second.m_weightedRefSpeed;
double const w = kv.second.m_weight;
if (my::AlmostEqualAbs(w, 0.0, kEps))
{
LOG(LWARNING, ("A traffic segment has zero weight."));
continue;
}
double const u = ws / w;
double const v = wrs / w;
bool const uz = my::AlmostEqualAbs(u, 0.0, kEps);
bool const vz = my::AlmostEqualAbs(v, 0.0, kEps);
if (uz && vz)
{
result[kv.first] = traffic::SpeedGroup::TempBlock;
}
else if (vz)
{
LOG(LWARNING, ("A traffic segment has zero reference speed."));
continue;
}
else
{
double p = 100.0 * u / v;
p = my::clamp(p, 0.0, 100.0);
result[kv.first] = traffic::GetSpeedGroupByPercentage(p);
}
}
return result;
}

string RoadSegmentIdRepr(traffic::TrafficInfo::RoadSegmentId const & v)
{
stringstream ss;
ostringstream ss;
ss << "RoadSegmentId(" << v.m_fid << ", " << v.m_idx << ", " << int(v.m_dir) << ")";
return ss.str();
}

boost::python::list GenerateTrafficKeys(string const & mwmPath)
{
vector<traffic::TrafficInfo::RoadSegmentId> result;
traffic::TrafficInfo::ExtractTrafficKeys(mwmPath, result);
return std_vector_to_python_list(result);
}

vector<uint8_t> GenerateTrafficValues(boost::python::list const & keys,
boost::python::dict const & segmentMappingDict)
{
vector<traffic::TrafficInfo::RoadSegmentId> keysVec =
python_list_to_std_vector<traffic::TrafficInfo::RoadSegmentId>(keys);
SegmentMapping segmentMapping;

boost::python::list mappingKeys = segmentMappingDict.keys();
for (size_t i = 0; i < len(mappingKeys); ++i)
{
object curArg = segmentMappingDict[mappingKeys[i]];
if (curArg)
segmentMapping[extract<traffic::TrafficInfo::RoadSegmentId>(mappingKeys[i])] =
extract<SegmentSpeeds>(segmentMappingDict[mappingKeys[i]]);
}

traffic::TrafficInfo::Coloring const knownColors = TransformToSpeedGroups(segmentMapping);
traffic::TrafficInfo::Coloring coloring;
traffic::TrafficInfo::CombineColorings(keysVec, knownColors, coloring);

vector<traffic::SpeedGroup> values(coloring.size());

size_t i = 0;
for (auto const & kv : coloring)
{
ASSERT_EQUAL(kv.first, keysVec[i], ());
values[i] = kv.second;
++i;
}
ASSERT_EQUAL(i, values.size(), ());

vector<uint8_t> buf;
traffic::TrafficInfo::SerializeTrafficValues(values, buf);
return buf;
}

void LoadClassificator(string const & classifPath)
{
GetPlatform().SetResourceDir(classifPath);
classificator::Load();
}
} // namespace

BOOST_PYTHON_MODULE(pytraffic)
Expand All @@ -40,10 +152,16 @@ BOOST_PYTHON_MODULE(pytraffic)
to_python_converter<vector<uint8_t>, vector_uint8t_to_str>();
vector_uint8t_from_python_str();

class_<SegmentSpeeds>("SegmentSpeeds", init<double, double, double>())
.def("__repr__", &SegmentSpeedsRepr);

class_<traffic::TrafficInfo::RoadSegmentId>("RoadSegmentId", init<uint32_t, uint16_t, uint8_t>())
.def("__repr__", &RoadSegmentIdRepr)
;

class_<std::vector<traffic::TrafficInfo::RoadSegmentId>>("RoadSegmentIdVec")
.def(vector_indexing_suite<std::vector<traffic::TrafficInfo::RoadSegmentId>>());

enum_<traffic::SpeedGroup>("SpeedGroup")
.value("G0", traffic::SpeedGroup::G0)
.value("G1", traffic::SpeedGroup::G1)
Expand All @@ -55,10 +173,7 @@ BOOST_PYTHON_MODULE(pytraffic)
.value("Unknown", traffic::SpeedGroup::Unknown)
;

class_<traffic::TrafficInfo::Coloring>("Coloring")
.def(map_indexing_suite<traffic::TrafficInfo::Coloring>())
;

def("dumps", Serialize);
def("loads", Deserialize);
def("load_classificator", LoadClassificator);
def("generate_traffic_keys", GenerateTrafficKeys);
def("generate_traffic_values", GenerateTrafficValues);
}
28 changes: 28 additions & 0 deletions traffic/pytraffic/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pytraffic import RoadSegmentId, SegmentSpeeds, load_classificator, generate_traffic_keys, generate_traffic_values
import argparse

parser = argparse.ArgumentParser(description='Example usage of pytraffic.')
parser.add_argument("--path_to_classificator", dest="path_to_classificator", help="Path to the directory that contains classificator.txt.")
parser.add_argument("--path_to_mwm", dest="path_to_mwm", help="Path to the target mwm file.")

options = parser.parse_args()
if not options.path_to_classificator or not options.path_to_mwm:
parser.print_help()
exit()

load_classificator(options.path_to_classificator)

keys = [
RoadSegmentId(0, 0, 0),
RoadSegmentId(1, 0, 0),
RoadSegmentId(1, 0, 1),
]

keys_from_mwm = generate_traffic_keys(options.path_to_mwm)

mapping = {
RoadSegmentId(0, 0, 0):SegmentSpeeds(1.0, 2.0, 3.0),
RoadSegmentId(1, 0, 1):SegmentSpeeds(4.0, 5.0, 6.0),
}

buf = generate_traffic_values(keys, mapping)
5 changes: 3 additions & 2 deletions traffic/traffic_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,9 @@ void TrafficInfo::ExtractTrafficKeys(string const & mwmPath, vector<RoadSegmentI
}

// static
void CombineColorings(vector<TrafficInfo::RoadSegmentId> const & keys,
TrafficInfo::Coloring const & knownColors, TrafficInfo::Coloring & result)
void TrafficInfo::CombineColorings(vector<TrafficInfo::RoadSegmentId> const & keys,
TrafficInfo::Coloring const & knownColors,
TrafficInfo::Coloring & result)
{
result.clear();
size_t numKnown = 0;
Expand Down

0 comments on commit ce69596

Please sign in to comment.