Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/openlr
diff options
context:
space:
mode:
authorSergey Magidovich <mgsergio@mapswithme.com>2017-07-18 16:42:22 +0300
committermpimenov <mpimenov@users.noreply.github.com>2017-07-24 12:29:10 +0300
commit953b416c858632143a018fd94cf376d04474508c (patch)
tree1a30195a5b2397b0ebfc376617592194e5b5bd24 /openlr
parentf064decfe875126c5eff946dfec2d9e6daedf9db (diff)
Store all data required by asssessment tool in one file.
Diffstat (limited to 'openlr')
-rw-r--r--openlr/CMakeLists.txt4
-rw-r--r--openlr/decoded_path.cpp162
-rw-r--r--openlr/decoded_path.hpp46
-rw-r--r--openlr/openlr.pro4
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp31
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.hpp2
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp213
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp50
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.cpp19
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.h2
-rw-r--r--openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.ui63
-rw-r--r--openlr/openlr_model_xml.cpp110
-rw-r--r--openlr/openlr_model_xml.hpp3
-rw-r--r--openlr/openlr_sample.cpp179
-rw-r--r--openlr/openlr_sample.hpp77
-rw-r--r--openlr/openlr_simple_decoder.cpp90
-rw-r--r--openlr/openlr_simple_decoder.hpp13
-rw-r--r--openlr/openlr_stat/openlr_stat.cpp114
-rw-r--r--openlr/openlr_tests/CMakeLists.txt12
-rw-r--r--openlr/openlr_tests/decoded_path_test.cpp224
-rw-r--r--openlr/openlr_tests/openlr_sample_test.cpp150
-rw-r--r--openlr/openlr_tests/openlr_tests.pro28
22 files changed, 792 insertions, 804 deletions
diff --git a/openlr/CMakeLists.txt b/openlr/CMakeLists.txt
index f1b30f4c4e..83aef00c2a 100644
--- a/openlr/CMakeLists.txt
+++ b/openlr/CMakeLists.txt
@@ -2,12 +2,12 @@ project(openlr)
set(
SRC
+ decoded_path.cpp
+ decoded_path.hpp
openlr_model.cpp
openlr_model.hpp
openlr_model_xml.cpp
openlr_model_xml.hpp
- openlr_sample.cpp
- openlr_sample.hpp
openlr_simple_decoder.cpp
openlr_simple_decoder.hpp
road_info_getter.cpp
diff --git a/openlr/decoded_path.cpp b/openlr/decoded_path.cpp
new file mode 100644
index 0000000000..ec5bbe7270
--- /dev/null
+++ b/openlr/decoded_path.cpp
@@ -0,0 +1,162 @@
+#include "openlr/decoded_path.hpp"
+
+#include "indexer/index.hpp"
+
+#include "platform/country_file.hpp"
+
+#include "geometry/latlon.hpp"
+#include "geometry/mercator.hpp"
+
+#include "base/assert.hpp"
+#include "base/string_utils.hpp"
+
+#define THROW_IF_NODE_IS_EMPTY(node, exc, msg) \
+ if (!node) \
+ MYTHROW(exc, msg)
+
+namespace
+{
+bool IsForwardFromXML(pugi::xml_node const & node)
+{
+ THROW_IF_NODE_IS_EMPTY(node, openlr::DecodedPathLoadError, ("Can't parse IsForward"));
+ return node.text().as_bool();
+}
+
+uint32_t SegmentIdFromXML(pugi::xml_node const & node)
+{
+ THROW_IF_NODE_IS_EMPTY(node, openlr::DecodedPathLoadError, ("Can't parse SegmentId"));
+ return node.text().as_uint();
+}
+
+void LatLonToXML(ms::LatLon const & latLon, pugi::xml_node & node)
+{
+ node.append_child("lat").text() = latLon.lat;
+ node.append_child("lon").text() = latLon.lon;
+}
+
+void LatLonFromXML(pugi::xml_node const & node, ms::LatLon & latLon)
+{
+ THROW_IF_NODE_IS_EMPTY(node, openlr::DecodedPathLoadError, ("Can't parse latLon"));
+ latLon.lat = node.child("lat").text().as_double();
+ latLon.lon = node.child("lon").text().as_double();
+}
+
+void FeatureIdFromXML(pugi::xml_node const & node, Index const & index, FeatureID & fid)
+{
+ THROW_IF_NODE_IS_EMPTY(node, openlr::DecodedPathLoadError, ("Can't parse CountryName"));
+ auto const countryName = node.child("CountryName").text().as_string();
+ fid.m_mwmId = index.GetMwmIdByCountryFile(platform::CountryFile(countryName));
+ fid.m_index = node.child("Index").text().as_uint();
+}
+
+void FeatureIdToXML(FeatureID const & fid, pugi::xml_node & node)
+{
+ node.append_child("CountryName").text() = fid.m_mwmId.GetInfo()->GetCountryName().data();
+ node.append_child("Index").text() = fid.m_index;
+}
+} // namespace
+
+namespace openlr
+{
+void WriteAsMappingForSpark(std::string const & fileName, std::vector<DecodedPath> const & paths)
+{
+ std::ofstream ost(fileName);
+ if (!ost.is_open())
+ MYTHROW(DecodedPathSaveError, ("Can't write to file", fileName, strerror(errno)));
+
+ WriteAsMappingForSpark(ost, paths);
+
+ if (ost.fail())
+ {
+ MYTHROW(DecodedPathSaveError,
+ ("An error occured while writing file", fileName, strerror(errno)));
+ }
+}
+
+void WriteAsMappingForSpark(std::ostream & ost, std::vector<DecodedPath> const & paths)
+{
+ ost << std::fixed; // Avoid scientific notation cause '-' is used as fields separator.
+ for (auto const & p : paths)
+ {
+ if (p.m_path.empty())
+ continue;
+
+ ost << p.m_segmentId.Get() << '\t';
+
+ auto const kFieldSep = '-';
+ auto const kSegmentSep = '=';
+ for (auto it = begin(p.m_path); it != end(p.m_path); ++it)
+ {
+ auto const & fid = it->GetFeatureId();
+ ost << fid.m_mwmId.GetInfo()->GetCountryName()
+ << kFieldSep << fid.m_index
+ << kFieldSep << it->GetSegId()
+ << kFieldSep << (it->IsForward() ? "fwd" : "bwd")
+ << kFieldSep << MercatorBounds::DistanceOnEarth(GetStart(*it), GetEnd(*it));
+
+ if (next(it) != end(p.m_path))
+ ost << kSegmentSep;
+ }
+ ost << endl;
+ }
+}
+
+void PathFromXML(pugi::xml_node const & node, Index const & index, Path & p)
+{
+ auto const edges = node.select_nodes("RoadEdge");
+ for (auto const xmlE : edges)
+ {
+ auto e = xmlE.node();
+
+ FeatureID fid;
+ FeatureIdFromXML(e.child("FeatureID"), index, fid);
+
+ auto const isForward = IsForwardFromXML(e.child("IsForward"));
+ auto const segmentId = SegmentIdFromXML(e.child("SegmentId"));
+
+ ms::LatLon start, end;
+ LatLonFromXML(e.child("StartJunction"), start);
+ LatLonFromXML(e.child("EndJunction"), end);
+
+ p.emplace_back(fid, isForward, segmentId,
+ routing::Junction(MercatorBounds::FromLatLon(start), 0 /* altitude */),
+ routing::Junction(MercatorBounds::FromLatLon(end), 0 /* altitude */));
+ }
+}
+
+void PathToXML(Path const & path, pugi::xml_node & node)
+{
+ for (auto const e : path)
+ {
+ auto edge = node.append_child("RoadEdge");
+
+ {
+ auto fid = edge.append_child("FeatureID");
+ FeatureIdToXML(e.GetFeatureId(), fid);
+ }
+
+ edge.append_child("IsForward").text() = e.IsForward();
+ edge.append_child("SegmentId").text() = e.GetSegId();
+ {
+ auto start = edge.append_child("StartJunction");
+ auto end = edge.append_child("EndJunction");
+ LatLonToXML(MercatorBounds::ToLatLon(GetStart(e)), start);
+ LatLonToXML(MercatorBounds::ToLatLon(GetEnd(e)), end);
+ }
+ }
+}
+} // namespace openlr
+
+namespace routing
+{
+std::vector<m2::PointD> GetPoints(openlr::Path const & p)
+{
+ CHECK(!p.empty(), ("Path should not be empty"));
+ std::vector<m2::PointD> points;
+ points.push_back(GetStart(p.front()));
+ for (auto const & e : p)
+ points.push_back(GetEnd(e));
+
+ return points;
+}
+} // namespace routing
diff --git a/openlr/decoded_path.hpp b/openlr/decoded_path.hpp
new file mode 100644
index 0000000000..1becd73276
--- /dev/null
+++ b/openlr/decoded_path.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "routing/road_graph.hpp"
+
+#include "base/exception.hpp"
+#include "base/newtype.hpp"
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "3party/pugixml/src/pugixml.hpp"
+
+class Index;
+
+namespace openlr
+{
+using Path = routing::RoadGraphBase::TEdgeVector;
+using routing::Edge;
+
+NEWTYPE(uint32_t, PartnerSegmentId);
+NEWTYPE_SIMPLE_OUTPUT(PartnerSegmentId);
+
+DECLARE_EXCEPTION(DecodedPathLoadError, RootException);
+DECLARE_EXCEPTION(DecodedPathSaveError, RootException);
+
+struct DecodedPath
+{
+ PartnerSegmentId m_segmentId;
+ Path m_path;
+};
+
+void WriteAsMappingForSpark(std::string const & fileName, std::vector<DecodedPath> const & paths);
+void WriteAsMappingForSpark(std::ostream & ost, std::vector<DecodedPath> const & paths);
+
+void PathFromXML(pugi::xml_node const & node, Index const & index, Path & path);
+void PathToXML(Path const & path, pugi::xml_node & node);
+} // namespace openlr
+
+namespace routing
+{
+inline m2::PointD GetStart(Edge const & e) { return e.GetStartJunction().GetPoint(); }
+inline m2::PointD GetEnd(Edge const & e) { return e.GetEndJunction().GetPoint(); }
+
+std::vector<m2::PointD> GetPoints(routing::RoadGraphBase::TEdgeVector const & p);
+} // namespace routing
diff --git a/openlr/openlr.pro b/openlr/openlr.pro
index e9f9649d8f..476edaca8d 100644
--- a/openlr/openlr.pro
+++ b/openlr/openlr.pro
@@ -8,18 +8,18 @@ ROOT_DIR = ..
include($$ROOT_DIR/common.pri)
SOURCES += \
+ decoded_path.cpp \
openlr_model.cpp \
openlr_model_xml.cpp \
- openlr_sample.cpp \
openlr_simple_decoder.cpp \
road_info_getter.cpp \
road_type_checkers.cpp \
router.cpp \
HEADERS += \
+ decoded_path.hpp \
openlr_model.hpp \
openlr_model_xml.hpp \
- openlr_sample.hpp \
openlr_simple_decoder.hpp \
road_info_getter.hpp \
road_type_checkers.hpp \
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp b/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp
index f2152d1727..6614c6410f 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp
@@ -22,8 +22,6 @@
namespace
{
-// TODO(mgsergio): Consider getting rid of this class: just put everything
-// in TrafficMode.
class TrafficDrawerDelegate : public TrafficDrawerDelegateBase
{
public:
@@ -38,10 +36,9 @@ public:
m_framework.SetViewportCenter(center);
}
- void DrawDecodedSegments(DecodedSample const & sample, int const sampleIndex) override
+ void DrawDecodedSegments(std::vector<m2::PointD> const & points) override
{
- CHECK(!sample.GetItems().empty(), ("Sample must not be empty."));
- auto const & points = sample.GetPoints(sampleIndex);
+ CHECK(!points.empty(), ("Points must not be empty."));
LOG(LINFO, ("Decoded segment", points));
m_drapeApi.AddLine(NextLineId(),
@@ -49,10 +46,8 @@ public:
.Width(3.0f).ShowPoints(true /* markPoints */));
}
- void DrawEncodedSegment(openlr::LinearSegment const & segment) override
+ void DrawEncodedSegment(std::vector<m2::PointD> const & points) override
{
- auto const & points = segment.GetMercatorPoints();
-
LOG(LINFO, ("Encoded segment", points));
m_drapeApi.AddLine(NextLineId(),
df::DrapeApiLineData(points, dp::Color(255, 0, 0, 255))
@@ -102,14 +97,14 @@ MainWindow::MainWindow(Framework & framework)
m_saveTrafficSampleAction->setEnabled(false /* enabled */);
}
-void MainWindow::CreateTrafficPanel(string const & dataFilePath, string const & sampleFilePath)
+void MainWindow::CreateTrafficPanel(string const & dataFilePath)
{
+ m_trafficMode = new TrafficMode(dataFilePath, m_framework.GetIndex(),
+ make_unique<TrafficDrawerDelegate>(m_framework));
+
m_docWidget = new QDockWidget(tr("Routes"), this);
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_docWidget);
- m_trafficMode = new TrafficMode(dataFilePath, sampleFilePath,
- m_framework.GetIndex(),
- make_unique<TrafficDrawerDelegate>(m_framework));
m_docWidget->setWidget(new TrafficPanel(m_trafficMode, m_docWidget));
m_docWidget->adjustSize();
@@ -133,7 +128,17 @@ void MainWindow::OnOpenTrafficSample()
if (dlg.result() != QDialog::DialogCode::Accepted)
return;
- CreateTrafficPanel(dlg.GetDataFilePath(), dlg.GetSampleFilePath());
+ try
+ {
+ CreateTrafficPanel(dlg.GetDataFilePath());
+ }
+ catch (TrafficModeError const & e)
+ {
+ QMessageBox::critical(this, "Data loading error", QString("Can't load data file."));
+ LOG(LERROR, (e.Msg()));
+ return;
+ }
+
m_closeTrafficSampleAction->setEnabled(true /* enabled */);
m_saveTrafficSampleAction->setEnabled(true /* enabled */);
}
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.hpp b/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.hpp
index f9e7dac26e..99b3f9dc5d 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.hpp
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.hpp
@@ -26,7 +26,7 @@ public:
MainWindow(Framework & framework);
private:
- void CreateTrafficPanel(std::string const & dataFilePath, std::string const & sampleFilePath);
+ void CreateTrafficPanel(std::string const & dataFilePath);
void DestroyTrafficPanel();
void OnOpenTrafficSample();
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp b/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp
index 63f933a1e7..84a0ac6797 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp
@@ -5,140 +5,87 @@
#include "indexer/index.hpp"
#include "indexer/scales.hpp"
+#include "base/macros.hpp"
#include "base/stl_add.hpp"
#include "3party/pugixml/src/pugixml.hpp"
-#include <QtCore/QItemSelection>
+#include <QItemSelection>
-
-// DecodedSample -----------------------------------------------------------------------------------
-DecodedSample::DecodedSample(Index const & index, openlr::SamplePool const & sample)
+namespace
{
- for (auto const & item : sample)
- {
- m_decodedItems.push_back(item);
- for (auto const & mwmSegment : item.m_segments)
- {
- auto const & fid = mwmSegment.m_fid;
- Index::FeaturesLoaderGuard g(index, fid.m_mwmId);
- CHECK(fid.m_mwmId.IsAlive(), ("Mwm id is not alive."));
- if (m_points.find(fid) != end(m_points))
- continue;
-
- FeatureType ft;
- CHECK(g.GetFeatureByIndex(fid.m_index, ft), ("Can't read feature", fid));
- ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
-
- auto & v = m_points[fid];
- v.reserve(ft.GetPointsCount());
- ft.ForEachPoint(MakeBackInsertFunctor(v), scales::GetUpperScale());
- }
- }
-}
-
-std::vector<m2::PointD> DecodedSample::GetPoints(size_t const index) const
+std::vector<m2::PointD> GetPoints(openlr::LinearSegment const & segment)
{
- std::vector<m2::PointD> points;
-
- auto const pushPoint = [&points](m2::PointD const & p)
- {
- if (points.empty() || !(points.back() - p).IsAlmostZero())
- points.push_back(p);
- };
-
- auto const & item = m_decodedItems[index];
- for (auto const & seg : item.m_segments)
- {
- auto const ftIt = m_points.find(seg.m_fid);
- CHECK(ftIt != end(m_points), ("Can't find feature with id:", seg.m_fid));
- auto const & ftPoints = ftIt->second;
- CHECK_LESS(seg.m_segId + 1, ftPoints.size(), ());
- auto const firstP = ftPoints[seg.m_segId];
- auto const secondP = ftPoints[seg.m_segId + 1];
- if (seg.m_isForward)
- {
- pushPoint(firstP);
- pushPoint(secondP);
- }
- else
- {
- pushPoint(secondP);
- pushPoint(firstP);
- }
- }
-
- return points;
+ std::vector<m2::PointD> result;
+ for (auto const & lrp : segment.m_locationReference.m_points)
+ result.push_back(MercatorBounds::FromLatLon(lrp.m_latLon));
+ return result;
+}
}
// TrafficMode -------------------------------------------------------------------------------------
-TrafficMode::TrafficMode(std::string const & dataFileName, std::string const & sampleFileName,
- Index const & index, std::unique_ptr<TrafficDrawerDelegateBase> drawerDelagate,
+TrafficMode::TrafficMode(std::string const & dataFileName, Index const & index,
+ std::unique_ptr<TrafficDrawerDelegateBase> drawerDelagate,
QObject * parent)
- : QAbstractTableModel(parent)
- , m_drawerDelegate(move(drawerDelagate))
+ : QAbstractTableModel(parent), m_index(index), m_drawerDelegate(move(drawerDelagate))
{
- try
- {
- auto const & sample = openlr::LoadSamplePool(sampleFileName, index);
- LOG(LINFO, ("Samples parsed:", sample.size()));
- m_decodedSample = make_unique<DecodedSample>(index, sample);
- LOG(LINFO, (m_decodedSample->GetItems().size(), "samples are loaded"));
- }
- catch (openlr::SamplePoolLoadError const & e)
- {
- LOG(LERROR, (e.Msg()));
- return;
- }
-
+ // TODO(mgsergio): Collect stat how many segments of each kind were parsed.
pugi::xml_document doc;
if (!doc.load_file(dataFileName.data()))
- {
- LOG(LERROR, ("Can't load file:", dataFileName));
- return;
- }
+ MYTHROW(TrafficModeError, ("Can't load file:", strerror(errno)));
+
+ // Select all Segment elements that are direct children of the context node.
+ auto const segments = doc.select_nodes("./Segment");
- std::vector<openlr::LinearSegment> segments;
- if (!ParseOpenlr(doc, segments))
+ try
{
- LOG(LERROR, ("Can't parse data:", dataFileName));
- return;
+ for (auto const xpathNode : segments)
+ {
+ m_segments.emplace_back();
+
+ auto const xmlSegment = xpathNode.node();
+ auto & segment = m_segments.back();
+
+ // TODO(mgsergio): Unify error handling interface of openlr_xml_mode and decoded_path parsers.
+ if (!openlr::SegmentFromXML(xmlSegment.child("reportSegments"), segment.GetPartnerSegment()))
+ MYTHROW(TrafficModeError, ("An error occured while parsing: can't parse segment"));
+
+ if (auto const route = xmlSegment.child("Route"))
+ {
+ auto & path = segment.GetMatchedPath();
+ path.emplace();
+ openlr::PathFromXML(route, m_index, *path);
+ }
+
+ if (auto const route = xmlSegment.child("FakeRoute"))
+ {
+ auto & path = segment.GetFakePath();
+ path.emplace();
+ openlr::PathFromXML(route, m_index, *path);
+ }
+ }
}
- for (auto const & segment : segments)
+ catch (openlr::DecodedPathLoadError const & e)
{
- CHECK(!segment.m_locationReference.m_points.empty(), ());
- m_partnerSegments[segment.m_segmentId] = segment;
+ MYTHROW(TrafficModeError, ("An exception occured while parsing", dataFileName, e.Msg()));
}
- LOG(LINFO, (m_partnerSegments.size(), "segments are loaded"));
- m_valid = true;
+
+ // TODO(mgsergio): LOG(LINFO, (xxx, "segments are loaded"));
}
bool TrafficMode::SaveSampleAs(std::string const & fileName) const
{
- try
- {
- auto const & samplePool = m_decodedSample->GetItems();
- openlr::SaveSamplePool(fileName, samplePool, true /* saveEvaluation */);
- }
- catch (openlr::SamplePoolSaveError const & e)
- {
- LOG(LERROR, (e.Msg()));
- return false;
- }
+ // TODO(mgsergio): Remove #include "base/macros.hpp" when implemented;
+ NOTIMPLEMENTED();
return true;
}
int TrafficMode::rowCount(const QModelIndex & parent) const
{
- if (!m_decodedSample)
- return 0;
- return static_cast<int>(m_decodedSample->m_decodedItems.size());
+ return static_cast<int>(m_segments.size());
}
-int TrafficMode::columnCount(const QModelIndex & parent) const
-{
- return 2;
-}
+int TrafficMode::columnCount(const QModelIndex & parent) const { return 1; }
QVariant TrafficMode::data(const QModelIndex & index, int role) const
{
@@ -152,10 +99,7 @@ QVariant TrafficMode::data(const QModelIndex & index, int role) const
return QVariant();
if (index.column() == 0)
- return ToString(m_decodedSample->m_decodedItems[index.row()].m_evaluation).data();
-
- if (index.column() == 1)
- return m_decodedSample->m_decodedItems[index.row()].m_partnerSegmentId.Get();
+ return m_segments[index.row()].GetPartnerSegmentId();
return QVariant();
}
@@ -163,37 +107,26 @@ QVariant TrafficMode::data(const QModelIndex & index, int role) const
void TrafficMode::OnItemSelected(QItemSelection const & selected, QItemSelection const &)
{
CHECK(!selected.empty(), ("The selection should not be empty. RTFM for qt5."));
- CHECK(!m_decodedSample->Empty(), ("No samples are loaded, can't select."));
+ CHECK(!m_segments.empty(), ("No segments are loaded, can't select."));
auto const row = selected.front().top();
// TODO(mgsergio): Use algo for center calculation.
// Now viewport is set to the first point of the first segment.
- CHECK_LESS(row, m_decodedSample->m_decodedItems.size(), ());
- auto & sampleItem = m_decodedSample->m_decodedItems[row];
- auto const partnerSegmentId = sampleItem.m_partnerSegmentId;
- LOG(LINFO, ("Partner segment id:", partnerSegmentId));
-
- if (sampleItem.m_segments.empty())
- {
- LOG(LERROR, ("Empty mwm segments for partner id", partnerSegmentId.Get()));
- return;
- }
+ CHECK_LESS(row, m_segments.size(), ());
+ auto & segment = m_segments[row];
+ auto const partnerSegmentId = segment.GetPartnerSegmentId();
- auto const & firstSegment = sampleItem.m_segments[0];
- auto const & firstSegmentFeatureId = firstSegment.m_fid;
- auto const & firstSegmentFeature = m_decodedSample->m_points.at(firstSegmentFeatureId);
+ // TODO(mgsergio): Maybe we shold show empty paths.
+ CHECK(segment.GetMatchedPath(), ("Empty mwm segments for partner id", partnerSegmentId));
- LOG(LDEBUG, ("PartnerSegmentId:", partnerSegmentId.Get(),
- "Segment points:", m_partnerSegments[partnerSegmentId.Get()].GetMercatorPoints(),
- "Featrue segment id", firstSegment.m_segId,
- "Feature segment points", firstSegmentFeature[firstSegment.m_segId],
- firstSegmentFeature[firstSegment.m_segId + 1]));
+ auto const & path = *segment.GetMatchedPath();
+ auto const & firstEdge = path.front();
m_drawerDelegate->Clear();
- m_drawerDelegate->SetViewportCenter(firstSegmentFeature[firstSegment.m_segId]);
- m_drawerDelegate->DrawEncodedSegment(m_partnerSegments.at(partnerSegmentId.Get()));
- m_drawerDelegate->DrawDecodedSegments(*m_decodedSample, row);
+ m_drawerDelegate->SetViewportCenter(GetStart(firstEdge));
+ m_drawerDelegate->DrawEncodedSegment(GetPoints(segment.GetPartnerSegment()));
+ m_drawerDelegate->DrawDecodedSegments(GetPoints(path));
}
Qt::ItemFlags TrafficMode::flags(QModelIndex const & index) const
@@ -201,23 +134,5 @@ Qt::ItemFlags TrafficMode::flags(QModelIndex const & index) const
if (!index.isValid())
return Qt::ItemIsEnabled;
- if (index.column() != 0)
- QAbstractItemModel::flags(index);
-
- return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
-}
-
-bool TrafficMode::setData(QModelIndex const & index, QVariant const & value, int const role)
-{
- if (!index.isValid() || role != Qt::EditRole)
- return false;
-
- auto const newValue = value.toString();
- auto evaluation = openlr::ParseItemEvaluation(newValue.toStdString());
- if (evaluation == openlr::ItemEvaluation::NotAValue)
- return false;
-
- m_decodedSample->m_decodedItems[index.row()].m_evaluation = evaluation;
- emit dataChanged(index, index);
- return true;
+ return QAbstractItemModel::flags(index);
}
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp b/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp
index b6fa4fe1ee..86816bfb77 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp
@@ -2,29 +2,44 @@
#include "indexer/feature.hpp"
+#include "openlr/decoded_path.hpp"
#include "openlr/openlr_model.hpp"
-#include "openlr/openlr_sample.hpp"
+#include "base/exception.hpp"
+
+#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>
-#include <QtCore/QAbstractTableModel>
+#include <boost/optional.hpp>
+
+#include <QAbstractTableModel>
class Index;
class QItemSelection;
+class Selection;
-struct DecodedSample
+DECLARE_EXCEPTION(TrafficModeError, RootException);
+
+class SegmentCorrespondence
{
- DecodedSample(Index const & index, openlr::SamplePool const & sample);
+public:
+ boost::optional<openlr::Path> const & GetMatchedPath() const { return m_matchedPath; }
+ boost::optional<openlr::Path> & GetMatchedPath() { return m_matchedPath; }
- bool Empty() const { return m_decodedItems.empty(); }
+ boost::optional<openlr::Path> const & GetFakePath() const { return m_fakePath; }
+ boost::optional<openlr::Path> & GetFakePath() { return m_fakePath; }
- openlr::SamplePool const & GetItems() const { return m_decodedItems; }
- std::vector<m2::PointD> GetPoints(size_t const index) const;
+ openlr::LinearSegment const & GetPartnerSegment() const { return m_partnerSegment; }
+ openlr::LinearSegment & GetPartnerSegment() { return m_partnerSegment; }
- std::map<FeatureID, std::vector<m2::PointD>> m_points;
- std::vector<openlr::SampleItem> m_decodedItems;
+ uint32_t GetPartnerSegmentId() const { return m_partnerSegment.m_segmentId; }
+
+private:
+ openlr::LinearSegment m_partnerSegment;
+ boost::optional<openlr::Path> m_matchedPath;
+ boost::optional<openlr::Path> m_fakePath;
};
/// This class is used to delegate segments drawing to the DrapeEngine.
@@ -35,8 +50,8 @@ public:
virtual void SetViewportCenter(m2::PointD const & center) = 0;
- virtual void DrawDecodedSegments(DecodedSample const & sample, int sampleIndex) = 0;
- virtual void DrawEncodedSegment(openlr::LinearSegment const & segment) = 0;
+ virtual void DrawDecodedSegments(std::vector<m2::PointD> const & points) = 0;
+ virtual void DrawEncodedSegment(std::vector<m2::PointD> const & points) = 0;
virtual void Clear() = 0;
};
@@ -47,12 +62,12 @@ class TrafficMode : public QAbstractTableModel
Q_OBJECT
public:
- TrafficMode(std::string const & dataFileName, std::string const & sampleFileName,
- Index const & index, std::unique_ptr<TrafficDrawerDelegateBase> drawerDelagate,
+ // TODO(mgsergio): Check we are on the right mwm. I.E. right mwm version an everything.
+ TrafficMode(std::string const & dataFileName, Index const & index,
+ std::unique_ptr<TrafficDrawerDelegateBase> drawerDelagate,
QObject * parent = Q_NULLPTR);
bool SaveSampleAs(std::string const & fileName) const;
- bool IsValid() const { return m_valid; }
int rowCount(const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE;
@@ -62,16 +77,13 @@ public:
// int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(QModelIndex const & index) const Q_DECL_OVERRIDE;
- bool setData(QModelIndex const & index, QVariant const & value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
public slots:
void OnItemSelected(QItemSelection const & selected, QItemSelection const &);
private:
- std::unique_ptr<DecodedSample> m_decodedSample;
- std::unordered_map<decltype(openlr::LinearSegment::m_segmentId), openlr::LinearSegment> m_partnerSegments;
+ Index const & m_index;
+ std::vector<SegmentCorrespondence> m_segments;
std::unique_ptr<TrafficDrawerDelegateBase> m_drawerDelegate;
-
- bool m_valid = false;
};
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.cpp b/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.cpp
index b144be3f0a..3b56bccfbf 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.cpp
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.cpp
@@ -7,8 +7,7 @@
namespace
{
-string const kDataFilePath = "LastTrafficDataFilePath";
-string const kSampleFilePath = "LastTrafficSampleFilePath";
+string const kDataFilePath = "LastOpenlrAssessmentDataFilePath";
} // namespace
TrafficModeInitDlg::TrafficModeInitDlg(QWidget * parent) :
@@ -18,19 +17,11 @@ TrafficModeInitDlg::TrafficModeInitDlg(QWidget * parent) :
m_ui->setupUi(this);
string lastDataFilePath;
- string lastSampleFilePath;
if (settings::Get(kDataFilePath, lastDataFilePath))
m_ui->dataFileName->setText(QString::fromStdString(lastDataFilePath));
- if (settings::Get(kSampleFilePath, lastSampleFilePath))
- m_ui->sampleFileName->setText(QString::fromStdString(lastSampleFilePath));
- connect(m_ui->chooseDataFileButton, &QPushButton::clicked, [this](bool)
- {
- SetFilePathViaDialog(*m_ui->dataFileName, tr("Choose traffic data file"), "*.xml");
- });
- connect(m_ui->chooseSampleFileButton, &QPushButton::clicked, [this](bool)
- {
- SetFilePathViaDialog(*m_ui->sampleFileName, tr("Choose traffic sample file"));
+ connect(m_ui->chooseDataFileButton, &QPushButton::clicked, [this](bool) {
+ SetFilePathViaDialog(*m_ui->dataFileName, tr("Choose data file"), "*.xml");
});
}
@@ -42,11 +33,7 @@ TrafficModeInitDlg::~TrafficModeInitDlg()
void TrafficModeInitDlg::accept()
{
m_dataFileName = m_ui->dataFileName->text().trimmed().toStdString();
- m_sampleFileName = m_ui->sampleFileName->text().trimmed().toStdString();
-
settings::Set(kDataFilePath, m_dataFileName);
- settings::Set(kSampleFilePath, m_sampleFileName);
-
QDialog::accept();
}
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.h b/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.h
index b790e626d7..8c17d8bdbf 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.h
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.h
@@ -19,7 +19,6 @@ public:
~TrafficModeInitDlg();
std::string GetDataFilePath() const { return m_dataFileName; }
- std::string GetSampleFilePath() const { return m_sampleFileName; }
private:
void SetFilePathViaDialog(QLineEdit & dest, QString const & title,
@@ -31,5 +30,4 @@ private:
Ui::TrafficModeInitDlg * m_ui;
std::string m_dataFileName;
- std::string m_sampleFileName;
};
diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.ui b/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.ui
index 1ce7c4fe58..a7821ff6a3 100644
--- a/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.ui
+++ b/openlr/openlr_match_quality/openlr_assessment_tool/trafficmodeinitdlg.ui
@@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
- <width>478</width>
- <height>130</height>
+ <width>482</width>
+ <height>122</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="windowTitle">
<string>Select traffic files</string>
</property>
@@ -22,62 +28,41 @@
<x>20</x>
<y>10</y>
<width>441</width>
- <height>111</height>
+ <height>101</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="2" column="3">
- <widget class="QPushButton" name="chooseSampleFileButton">
- <property name="text">
- <string>Choose...</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="dataLabel">
- <property name="mouseTracking">
- <bool>true</bool>
- </property>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="cancelButton">
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Traffic data:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>Cancel</string>
</property>
</widget>
</item>
- <item row="0" column="1" colspan="2">
- <widget class="QLineEdit" name="dataFileName"/>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLineEdit" name="sampleFileName">
+ <item row="0" column="3">
+ <widget class="QPushButton" name="chooseDataFileButton">
<property name="text">
- <string/>
+ <string>Choose...</string>
</property>
</widget>
</item>
- <item row="3" column="3">
+ <item row="1" column="3">
<widget class="QPushButton" name="okButton">
<property name="text">
<string>Ok</string>
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Traffic sample:</string>
- </property>
- </widget>
+ <item row="0" column="1" colspan="2">
+ <widget class="QLineEdit" name="dataFileName"/>
</item>
- <item row="0" column="3">
- <widget class="QPushButton" name="chooseDataFileButton">
- <property name="text">
- <string>Choose...</string>
+ <item row="0" column="0">
+ <widget class="QLabel" name="dataLabel">
+ <property name="mouseTracking">
+ <bool>true</bool>
</property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QPushButton" name="cancelButton">
<property name="text">
- <string>Cancel</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Data file:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@@ -87,8 +72,6 @@
<tabstops>
<tabstop>dataFileName</tabstop>
<tabstop>chooseDataFileButton</tabstop>
- <tabstop>sampleFileName</tabstop>
- <tabstop>chooseSampleFileButton</tabstop>
</tabstops>
<resources/>
<connections>
diff --git a/openlr/openlr_model_xml.cpp b/openlr/openlr_model_xml.cpp
index daa28f8950..19a6deab93 100644
--- a/openlr/openlr_model_xml.cpp
+++ b/openlr/openlr_model_xml.cpp
@@ -13,7 +13,7 @@
namespace // Primitive utilities to handle simple OpenLR-like XML data.
{
template <typename Value>
-bool ParseInteger(pugi::xml_node const & node, Value & value)
+bool IntegerFromXML(pugi::xml_node const & node, Value & value)
{
if (!node)
return false;
@@ -25,8 +25,8 @@ bool ParseInteger(pugi::xml_node const & node, Value & value)
bool GetLatLon(pugi::xml_node const & node, int32_t & lat, int32_t & lon)
{
- if (!ParseInteger(node.child("olr:latitude"), lat) ||
- !ParseInteger(node.child("olr:longitude"), lon))
+ if (!IntegerFromXML(node.child("olr:latitude"), lat) ||
+ !IntegerFromXML(node.child("olr:longitude"), lon))
{
return false;
}
@@ -37,7 +37,7 @@ bool GetLatLon(pugi::xml_node const & node, int32_t & lat, int32_t & lon)
// This helper is used to parse records like this:
// <olr:lfrcnp olr:table="olr001_FunctionalRoadClass" olr:code="4"/>
template <typename Value>
-bool ParseTableValue(pugi::xml_node const & node, Value & value)
+bool TableValueFromXML(pugi::xml_node const & node, Value & value)
{
if (!node)
return false;
@@ -58,10 +58,10 @@ pugi::xml_node GetLinearLocationReference(pugi::xml_node const & node)
// <value>integer<value>
// </node>
template <typename Value>
-bool ParseValue(pugi::xml_node const & node, Value & value)
+bool ValueFromXML(pugi::xml_node const & node, Value & value)
{
auto const valueNode = node.child("olr:value");
- return ParseInteger(valueNode, value);
+ return IntegerFromXML(valueNode, value);
}
template <typename Value>
@@ -69,13 +69,13 @@ bool ParseValueIfExists(pugi::xml_node const & node, Value & value)
{
if (!node)
return true;
- return ParseValue(node, value);
+ return ValueFromXML(node, value);
}
} // namespace
namespace // OpenLR tools and abstractions
{
-bool GetFirstCoordinate(pugi::xml_node const & node, ms::LatLon & latLon)
+bool FirstCoordinateFromXML(pugi::xml_node const & node, ms::LatLon & latLon)
{
int32_t lat, lon;
if (!GetLatLon(node.child("olr:coordinate"), lat, lon))
@@ -87,7 +87,8 @@ bool GetFirstCoordinate(pugi::xml_node const & node, ms::LatLon & latLon)
return true;
}
-bool GetCoordinate(pugi::xml_node const & node, ms::LatLon const & firstCoord, ms::LatLon & latLon)
+bool CoordinateFromXML(pugi::xml_node const & node, ms::LatLon const & firstCoord,
+ ms::LatLon & latLon)
{
int32_t lat, lon;
if (!GetLatLon(node.child("olr:coordinate"), lat, lon))
@@ -99,8 +100,8 @@ bool GetCoordinate(pugi::xml_node const & node, ms::LatLon const & firstCoord, m
return true;
}
-bool ParseLineProperties(pugi::xml_node const & linePropNode,
- openlr::LocationReferencePoint & locPoint)
+bool LinePropertiesFromXML(pugi::xml_node const & linePropNode,
+ openlr::LocationReferencePoint & locPoint)
{
if (!linePropNode)
{
@@ -108,19 +109,19 @@ bool ParseLineProperties(pugi::xml_node const & linePropNode,
return false;
}
- if (!ParseTableValue(linePropNode.child("olr:frc"), locPoint.m_functionalRoadClass))
+ if (!TableValueFromXML(linePropNode.child("olr:frc"), locPoint.m_functionalRoadClass))
{
LOG(LERROR, ("Can't parse functional road class"));
return false;
}
- if (!ParseTableValue(linePropNode.child("olr:fow"), locPoint.m_formOfWay))
+ if (!TableValueFromXML(linePropNode.child("olr:fow"), locPoint.m_formOfWay))
{
LOG(LERROR, ("Can't parse form of a way"));
return false;
}
- if (!ParseValue(linePropNode.child("olr:bearing"), locPoint.m_bearing))
+ if (!ValueFromXML(linePropNode.child("olr:bearing"), locPoint.m_bearing))
{
LOG(LERROR, ("Can't parse bearing"));
return false;
@@ -129,8 +130,8 @@ bool ParseLineProperties(pugi::xml_node const & linePropNode,
return true;
}
-bool ParsePathProperties(pugi::xml_node const & locPointNode,
- openlr::LocationReferencePoint & locPoint)
+bool PathPropertiesFromXML(pugi::xml_node const & locPointNode,
+ openlr::LocationReferencePoint & locPoint)
{
// Last point does not contain path properties.
if (strcmp(locPointNode.name(), "olr:last") == 0)
@@ -143,13 +144,13 @@ bool ParsePathProperties(pugi::xml_node const & locPointNode,
return false;
}
- if (!ParseValue(propNode.child("olr:dnp"), locPoint.m_distanceToNextPoint))
+ if (!ValueFromXML(propNode.child("olr:dnp"), locPoint.m_distanceToNextPoint))
{
LOG(LERROR, ("Can't parse dnp"));
return false;
}
- if (!ParseTableValue(propNode.child("olr:lfrcnp"), locPoint.m_lfrcnp))
+ if (!TableValueFromXML(propNode.child("olr:lfrcnp"), locPoint.m_lfrcnp))
{
LOG(LERROR, ("Can't parse lfrcnp"));
return false;
@@ -166,34 +167,35 @@ bool ParsePathProperties(pugi::xml_node const & locPointNode,
return true;
}
-bool ParseLocationReferencePoint(pugi::xml_node const & locPointNode,
- openlr::LocationReferencePoint & locPoint)
+bool LocationReferencePointFromXML(pugi::xml_node const & locPointNode,
+ openlr::LocationReferencePoint & locPoint)
{
- if (!GetFirstCoordinate(locPointNode, locPoint.m_latLon))
+ if (!FirstCoordinateFromXML(locPointNode, locPoint.m_latLon))
{
LOG(LERROR, ("Can't get first coordinate"));
return false;
}
- return ParseLineProperties(locPointNode.child("olr:lineProperties"), locPoint) &&
- ParsePathProperties(locPointNode, locPoint);
+ return LinePropertiesFromXML(locPointNode.child("olr:lineProperties"), locPoint) &&
+ PathPropertiesFromXML(locPointNode, locPoint);
}
-bool ParseLocationReferencePoint(pugi::xml_node const & locPointNode, ms::LatLon const & firstPoint,
- openlr::LocationReferencePoint & locPoint)
+bool LocationReferencePointFromXML(pugi::xml_node const & locPointNode,
+ ms::LatLon const & firstPoint,
+ openlr::LocationReferencePoint & locPoint)
{
- if (!GetCoordinate(locPointNode, firstPoint, locPoint.m_latLon))
+ if (!CoordinateFromXML(locPointNode, firstPoint, locPoint.m_latLon))
{
LOG(LERROR, ("Can't get last coordinate"));
return false;
}
- return ParseLineProperties(locPointNode.child("olr:lineProperties"), locPoint) &&
- ParsePathProperties(locPointNode, locPoint);
+ return LinePropertiesFromXML(locPointNode.child("olr:lineProperties"), locPoint) &&
+ PathPropertiesFromXML(locPointNode, locPoint);
}
-bool ParseLinearLocationReference(pugi::xml_node const & locRefNode,
- openlr::LinearLocationReference & locRef)
+bool LinearLocationReferenceFromXML(pugi::xml_node const & locRefNode,
+ openlr::LinearLocationReference & locRef)
{
if (!locRefNode)
{
@@ -203,7 +205,7 @@ bool ParseLinearLocationReference(pugi::xml_node const & locRefNode,
{
openlr::LocationReferencePoint point;
- if (!ParseLocationReferencePoint(locRefNode.child("olr:first"), point))
+ if (!LocationReferencePointFromXML(locRefNode.child("olr:first"), point))
return false;
locRef.m_points.push_back(point);
}
@@ -211,15 +213,15 @@ bool ParseLinearLocationReference(pugi::xml_node const & locRefNode,
for (auto const pointNode : locRefNode.select_nodes("olr:intermediates"))
{
openlr::LocationReferencePoint point;
- if (!ParseLocationReferencePoint(pointNode.node(), locRef.m_points.back().m_latLon, point))
+ if (!LocationReferencePointFromXML(pointNode.node(), locRef.m_points.back().m_latLon, point))
return false;
locRef.m_points.push_back(point);
}
{
openlr::LocationReferencePoint point;
- if (!ParseLocationReferencePoint(locRefNode.child("olr:last"), locRef.m_points.back().m_latLon,
- point))
+ if (!LocationReferencePointFromXML(locRefNode.child("olr:last"),
+ locRef.m_points.back().m_latLon, point))
return false;
locRef.m_points.push_back(point);
}
@@ -238,38 +240,38 @@ bool ParseLinearLocationReference(pugi::xml_node const & locRefNode,
return true;
}
-
-bool ParseSegment(pugi::xml_node const & segmentNode, openlr::LinearSegment & segment)
-{
- if (!ParseInteger(segmentNode.child("ReportSegmentID"), segment.m_segmentId))
- {
- LOG(LERROR, ("Can't parse segment id"));
- return false;
- }
-
- if (!ParseInteger(segmentNode.child("segmentLength"), segment.m_segmentLengthMeters))
- {
- LOG(LERROR, ("Can't parse segment length"));
- return false;
- }
-
- auto const locRefNode = GetLinearLocationReference(segmentNode);
- return ParseLinearLocationReference(locRefNode, segment.m_locationReference);
-}
} // namespace
namespace openlr
{
-// Functions ---------------------------------------------------------------------------------------
bool ParseOpenlr(pugi::xml_document const & document, vector<LinearSegment> & segments)
{
for (auto const segmentXpathNode : document.select_nodes("//reportSegments"))
{
LinearSegment segment;
- if (!ParseSegment(segmentXpathNode.node(), segment))
+ if (!SegmentFromXML(segmentXpathNode.node(), segment))
return false;
segments.push_back(segment);
}
return true;
}
+
+bool SegmentFromXML(pugi::xml_node const & segmentNode, LinearSegment & segment)
+{
+ CHECK(segmentNode, ());
+ if (!IntegerFromXML(segmentNode.child("ReportSegmentID"), segment.m_segmentId))
+ {
+ LOG(LERROR, ("Can't parse segment id"));
+ return false;
+ }
+
+ if (!IntegerFromXML(segmentNode.child("segmentLength"), segment.m_segmentLengthMeters))
+ {
+ LOG(LERROR, ("Can't parse segment length"));
+ return false;
+ }
+
+ auto const locRefNode = GetLinearLocationReference(segmentNode);
+ return LinearLocationReferenceFromXML(locRefNode, segment.m_locationReference);
+}
} // namespace openlr
diff --git a/openlr/openlr_model_xml.hpp b/openlr/openlr_model_xml.hpp
index 24add66771..660cd3fdd1 100644
--- a/openlr/openlr_model_xml.hpp
+++ b/openlr/openlr_model_xml.hpp
@@ -5,11 +5,14 @@
namespace pugi
{
class xml_document;
+class xml_node;
} // namespace pugi
namespace openlr
{
struct LinearSegment;
+bool SegmentFromXML(pugi::xml_node const & segmentNode, LinearSegment & segment);
+
bool ParseOpenlr(pugi::xml_document const & document, vector<LinearSegment> & segments);
} // namespace openlr
diff --git a/openlr/openlr_sample.cpp b/openlr/openlr_sample.cpp
deleted file mode 100644
index 76d4248766..0000000000
--- a/openlr/openlr_sample.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-#include "openlr/openlr_sample.hpp"
-
-#include "indexer/index.hpp"
-
-#include "base/string_utils.hpp"
-
-#include <cerrno>
-#include <cstring>
-#include <fstream>
-
-namespace
-{
-void ParseMWMSegments(std::string const & line, uint32_t const lineNumber,
- std::vector<openlr::SampleItem::MWMSegment> & segments, Index const & index)
-{
- std::vector<string> parts;
- strings::ParseCSVRow(line, '=', parts);
-
- for (auto const & seg : parts)
- {
- std::vector<string> segParts;
- strings::ParseCSVRow(seg, '-', segParts);
- CHECK_EQUAL(segParts.size(), 5, ());
-
- auto const mwmId = index.GetMwmIdByCountryFile(platform::CountryFile(segParts[0]));
-
- uint32_t featureIndex;
- if (!strings::to_uint(segParts[1], featureIndex))
- {
- MYTHROW(openlr::SamplePoolLoadError, ("Can't parse feature index of MWMSegment: uint expected",
- seg, "uint expected, got:", segParts[1],
- "line:", lineNumber));
- }
-
- uint32_t segId;
- if (!strings::to_uint(segParts[2], segId))
- {
- MYTHROW(openlr::SamplePoolLoadError, ("Can't parse segment id of MWMSegment:",
- seg, "uint expected, got:", segParts[2],
- "line:", lineNumber));
- }
-
- bool const isForward = (segParts[3] == "fwd");
- double length = 0;
- if (!strings::to_double(segParts[4], length))
- {
- MYTHROW(openlr::SamplePoolLoadError, ("Can't parse segment length of MWMSegment:",
- seg, "double expected, got:", segParts[4],
- "line:", lineNumber));
- }
-
- segments.push_back({FeatureID(mwmId, featureIndex), segId, isForward, length});
- }
-}
-
-void ParseSampleItem(std::string const & line, uint32_t const lineNumber, openlr::SampleItem & item,
- Index const & index)
-{
- std::vector<string> parts;
- strings::ParseCSVRow(line, '\t', parts);
- CHECK_GREATER_OR_EQUAL(parts.size(), 2, ());
- CHECK_LESS_OR_EQUAL(parts.size(), 3, ());
-
- auto nextFieldIndex = 0;
- if (parts.size() == 3)
- {
- item.m_evaluation = openlr::ParseItemEvaluation(parts[nextFieldIndex]);
- ++nextFieldIndex;
- }
- else
- {
- item.m_evaluation = openlr::ItemEvaluation::Unevaluated;
- }
-
- if (!strings::to_uint(parts[nextFieldIndex], item.m_partnerSegmentId.Get()))
- {
- MYTHROW(openlr::SamplePoolLoadError, ("Error: can't parse field", nextFieldIndex,
- "(number expected) in line:", lineNumber));
- }
- ++nextFieldIndex;
-
- ParseMWMSegments(parts[nextFieldIndex], lineNumber, item.m_segments, index);
-}
-} // namepsace
-
-namespace openlr
-{
-ItemEvaluation ParseItemEvaluation(std::string const & s)
-{
- if (s == "Unevaluated")
- return openlr::ItemEvaluation::Unevaluated;
-
- if (s == "Positive")
- return openlr::ItemEvaluation::Positive;
-
- if (s == "Negative")
- return openlr::ItemEvaluation::Negative;
-
- if (s == "RelPositive")
- return openlr::ItemEvaluation::RelPositive;
-
- if (s == "RelNegative")
- return openlr::ItemEvaluation::RelNegative;
-
- if (s == "Ignore")
- return openlr::ItemEvaluation::Ignore;
-
- return openlr::ItemEvaluation::NotAValue;
-}
-
-std::string ToString(ItemEvaluation const e)
-{
- switch (e)
- {
- case openlr::ItemEvaluation::Unevaluated: return "Unevaluated";
- case openlr::ItemEvaluation::Positive: return "Positive";
- case openlr::ItemEvaluation::Negative: return "Negative";
- case openlr::ItemEvaluation::RelPositive: return "RelPositive";
- case openlr::ItemEvaluation::RelNegative: return "RelNegative";
- case openlr::ItemEvaluation::Ignore: return "Ignore";
- default: return "NotAValue";
- }
-}
-
-SamplePool LoadSamplePool(std::string const & fileName, Index const & index)
-{
- std::ifstream sample(fileName);
- if (!sample.is_open())
- MYTHROW(SamplePoolLoadError, ("Can't read from file", fileName, strerror(errno)));
-
- SamplePool pool;
- for (struct {uint32_t lineNumber = 0; string line; } st; getline(sample, st.line); ++st.lineNumber)
- {
- SampleItem item = SampleItem::Uninitialized();
- ParseSampleItem(st.line, st.lineNumber, item, index);
- pool.push_back(item);
- }
-
- if (sample.fail() && !sample.eof())
- MYTHROW(SamplePoolLoadError, ("Can't read from file", fileName, strerror(errno)));
-
- if (pool.empty())
- MYTHROW(SamplePoolLoadError, ("No sample is read,", fileName, "probably empty"));
-
- return pool;
-}
-
-void SaveSamplePool(std::string const & fileName, SamplePool const & sample,
- bool const saveEvaluation)
-{
- LOG(LDEBUG, ("Saving sample to file:", fileName));
- std::ofstream out(fileName);
- if (!out.is_open())
- MYTHROW(SamplePoolSaveError, ("Can't write to file", fileName, strerror(errno)));
- out << std::fixed; // Avoid scientific notation cause '-' is used as fields separator.
- for (auto const & item : sample)
- {
- if (saveEvaluation)
- out << ToString(item.m_evaluation) << '\t';
-
- out << item.m_partnerSegmentId.Get() << '\t';
-
- for (auto it = begin(item.m_segments); it != end(item.m_segments); ++it)
- {
- auto const & fid = it->m_fid;
- out << fid.m_mwmId.GetInfo()->GetCountryName() << '-'
- << fid.m_index << '-' << it->m_segId
- << '-' << (it->m_isForward ? "fwd" : "bwd")
- << '-' << it->m_length;
-
- if (next(it) != end(item.m_segments))
- out << '=';
- }
- out << endl;
- }
- if (out.fail())
- MYTHROW(SamplePoolSaveError, ("An error occured while writing file", fileName, strerror(errno)));
-}
-} // namespace openlr
diff --git a/openlr/openlr_sample.hpp b/openlr/openlr_sample.hpp
deleted file mode 100644
index a937dac1b3..0000000000
--- a/openlr/openlr_sample.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#pragma once
-
-#include "indexer/feature_decl.hpp"
-
-#include "base/exception.hpp"
-#include "base/newtype.hpp"
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-class Index;
-
-namespace openlr
-{
-NEWTYPE(uint32_t, PartnerSegmentId);
-NEWTYPE_SIMPLE_OUTPUT(PartnerSegmentId);
-
-enum class ItemEvaluation
-{
- Unevaluated,
- Positive,
- Negative,
- RelPositive,
- RelNegative,
- Ignore,
- NotAValue
-};
-
-ItemEvaluation ParseItemEvaluation(std::string const & s);
-std::string ToString(ItemEvaluation const e);
-
-struct SampleItem
-{
- struct MWMSegment
- {
- MWMSegment(FeatureID const & fid, uint32_t const segId, bool const isForward,
- double const length)
- : m_fid(fid)
- , m_segId(segId)
- , m_isForward(isForward)
- , m_length(length)
- {
- }
-
- FeatureID const m_fid;
- uint32_t const m_segId;
- bool const m_isForward;
- double const m_length;
- };
-
- explicit SampleItem(PartnerSegmentId const partnerSegmentId,
- ItemEvaluation const evaluation = ItemEvaluation::Unevaluated)
- : m_partnerSegmentId(partnerSegmentId)
- , m_evaluation(evaluation)
- {
- }
-
- static SampleItem Uninitialized() { return {}; }
-
- PartnerSegmentId m_partnerSegmentId;
- std::vector<MWMSegment> m_segments;
- ItemEvaluation m_evaluation;
-
-private:
- SampleItem() = default;
-};
-
-DECLARE_EXCEPTION(SamplePoolLoadError, RootException);
-DECLARE_EXCEPTION(SamplePoolSaveError, RootException);
-
-using SamplePool = std::vector<SampleItem>;
-
-SamplePool LoadSamplePool(std::string const & fileName, Index const & index);
-void SaveSamplePool(std::string const & fileName, SamplePool const & sample,
- bool const saveEvaluation);
-} // namespace openlr
diff --git a/openlr/openlr_simple_decoder.cpp b/openlr/openlr_simple_decoder.cpp
index 1eb2874482..c1bd14c863 100644
--- a/openlr/openlr_simple_decoder.cpp
+++ b/openlr/openlr_simple_decoder.cpp
@@ -1,8 +1,7 @@
#include "openlr/openlr_simple_decoder.hpp"
+#include "openlr/decoded_path.hpp"
#include "openlr/openlr_model.hpp"
-#include "openlr/openlr_model_xml.hpp"
-#include "openlr/openlr_sample.hpp"
#include "openlr/road_info_getter.hpp"
#include "openlr/router.hpp"
#include "openlr/way_point.hpp"
@@ -20,7 +19,6 @@
#include "base/logging.hpp"
#include "base/math.hpp"
-#include "std/algorithm.hpp"
#include "std/fstream.hpp"
#include "std/thread.hpp"
@@ -51,50 +49,6 @@ struct alignas(kCacheLineSize) Stats
uint32_t m_tightOffsets = 0;
uint32_t m_total = 0;
};
-
-void SaveNonMatchedIds(string const & filename, std::vector<LinearSegment> const & segments,
- std::vector<IRoadGraph::TEdgeVector> const & paths)
-{
- CHECK_EQUAL(segments.size(), paths.size(), ());
-
- if (filename.empty())
- return;
-
- ofstream ofs(filename);
- for (size_t i = 0; i < segments.size(); ++i)
- {
- if (paths[i].empty())
- ofs << segments[i].m_segmentId << endl;
- }
-}
-
-openlr::SamplePool MakeSamplePool(std::vector<LinearSegment> const & segments,
- std::vector<IRoadGraph::TEdgeVector> const & paths)
-{
- openlr::SamplePool pool;
- for (size_t i = 0; i < segments.size(); ++i)
- {
- auto const & segment = segments[i];
- auto const & path = paths[i];
-
- if (path.empty())
- continue;
-
- pool.emplace_back(openlr::PartnerSegmentId(segment.m_segmentId));
- auto & sampleItem = pool.back();
-
- for (auto const & edge : path)
- {
- CHECK(!edge.IsFake(), ("There should be no fake edges in the path."));
-
- sampleItem.m_segments.emplace_back(
- edge.GetFeatureId(), edge.GetSegId(), edge.IsForward(),
- MercatorBounds::DistanceOnEarth(edge.GetStartJunction().GetPoint(),
- edge.GetEndJunction().GetPoint()));
- }
- }
- return pool;
-}
} // namespace
// OpenLRSimpleDecoder::SegmentsFilter -------------------------------------------------------------
@@ -123,40 +77,13 @@ bool OpenLRSimpleDecoder::SegmentsFilter::Matches(LinearSegment const & segment)
}
// OpenLRSimpleDecoder -----------------------------------------------------------------------------
-// static
-int const OpenLRSimpleDecoder::kHandleAllSegments = -1;
+OpenLRSimpleDecoder::OpenLRSimpleDecoder(vector<Index> const & indexes) : m_indexes(indexes) {}
-OpenLRSimpleDecoder::OpenLRSimpleDecoder(string const & dataFilename, vector<Index> const & indexes)
- : m_indexes(indexes)
-{
- auto const load_result = m_document.load_file(dataFilename.data());
- if (!load_result)
- MYTHROW(DecoderError, ("Can't load file", dataFilename, ":", load_result.description()));
-}
-
-void OpenLRSimpleDecoder::Decode(string const & outputFilename,
- string const & nonMatchedIdsFilename, int const segmentsToHandle,
- SegmentsFilter const & filter, uint32_t const numThreads)
+void OpenLRSimpleDecoder::Decode(std::vector<LinearSegment> const & segments,
+ uint32_t const numThreads, std::vector<DecodedPath> & paths)
{
double const kOffsetToleranceM = 10;
- // TODO(mgsergio): Feed segments directly to the decoder. Parsing should not
- // take place inside decoder process.
- vector<LinearSegment> segments;
- if (!ParseOpenlr(m_document, segments))
- MYTHROW(DecoderError, ("Can't parse data."));
-
- my::EraseIf(segments,
- [&filter](LinearSegment const & segment) { return !filter.Matches(segment); });
-
- if (segmentsToHandle != kHandleAllSegments && segmentsToHandle >= 0 &&
- static_cast<size_t>(segmentsToHandle) < segments.size())
- segments.resize(segmentsToHandle);
-
- sort(segments.begin(), segments.end(), my::LessBy(&LinearSegment::m_segmentId));
-
- vector<IRoadGraph::TEdgeVector> paths(segments.size());
-
// This code computes the most optimal (in the sense of cache lines
// occupancy) batch size.
size_t constexpr a = my::LCM(sizeof(LinearSegment), kCacheLineSize) / sizeof(LinearSegment);
@@ -183,6 +110,8 @@ void OpenLRSimpleDecoder::Decode(string const & outputFilename,
auto const & segment = segments[j];
auto const & ref = segment.m_locationReference;
+ paths[j].m_segmentId.Set(segment.m_segmentId);
+
points.clear();
for (auto const & point : ref.m_points)
points.emplace_back(point);
@@ -223,7 +152,7 @@ void OpenLRSimpleDecoder::Decode(string const & outputFilename,
}
}
- auto & path = paths[j];
+ auto & path = paths[j].m_path;
if (!router.Go(points, positiveOffsetM, negativeOffsetM, path))
++stats.m_routeIsNotCalculated;
@@ -246,11 +175,6 @@ void OpenLRSimpleDecoder::Decode(string const & outputFilename,
for (auto & worker : workers)
worker.join();
- SaveNonMatchedIds(nonMatchedIdsFilename, segments, paths);
-
- auto const samplePool = MakeSamplePool(segments, paths);
- SaveSamplePool(outputFilename, samplePool, false /* saveEvaluation */);
-
Stats allStats;
for (auto const & s : stats)
allStats.Add(s);
diff --git a/openlr/openlr_simple_decoder.hpp b/openlr/openlr_simple_decoder.hpp
index 67db5c6dd8..82911ddd02 100644
--- a/openlr/openlr_simple_decoder.hpp
+++ b/openlr/openlr_simple_decoder.hpp
@@ -2,7 +2,7 @@
#include "base/exception.hpp"
-#include "3party/pugixml/src/pugixml.hpp"
+#include <routing/road_graph.hpp>
#include <cstdint>
#include <string>
@@ -14,6 +14,7 @@ class Index;
namespace openlr
{
struct LinearSegment;
+struct DecodedPath;
DECLARE_EXCEPTION(DecoderError, RootException);
@@ -33,15 +34,13 @@ public:
bool const m_multipointsOnly;
};
- static int const kHandleAllSegments;
+ OpenLRSimpleDecoder(std::vector<Index> const & indexes);
- OpenLRSimpleDecoder(std::string const & dataFilename, std::vector<Index> const & indexes);
-
- void Decode(std::string const & outputFilename, std::string const & nonMatchedIdsFilename,
- int segmentsToHandle, SegmentsFilter const & filter, uint32_t numThreads);
+ // Maps partner segments to mwm paths. |segments| should be sorted by partner id.
+ void Decode(std::vector<LinearSegment> const & segments, uint32_t const numThreads,
+ std::vector<DecodedPath> & paths);
private:
std::vector<Index> const & m_indexes;
- pugi::xml_document m_document;
};
} // namespace openlr
diff --git a/openlr/openlr_stat/openlr_stat.cpp b/openlr/openlr_stat/openlr_stat.cpp
index f2d132e050..fbff196e11 100644
--- a/openlr/openlr_stat/openlr_stat.cpp
+++ b/openlr/openlr_stat/openlr_stat.cpp
@@ -1,5 +1,7 @@
#include "openlr/openlr_simple_decoder.hpp"
+#include "routing/road_graph.hpp"
+
#include "indexer/classificator_loader.hpp"
#include "indexer/index.hpp"
@@ -7,17 +9,30 @@
#include "platform/local_country_file_utils.hpp"
#include "platform/platform.hpp"
+#include "openlr/decoded_path.hpp"
+#include "openlr/openlr_model.hpp"
+#include "openlr/openlr_model_xml.hpp"
+
#include "coding/file_name_utils.hpp"
+#include "base/stl_helpers.hpp"
+
#include "3party/gflags/src/gflags/gflags.h"
+#include "3party/pugixml/src/pugixml.hpp"
+#include <algorithm>
#include <cstdint>
#include <cstdio>
+#include <fstream>
#include <string>
+#include <unordered_map>
#include <vector>
DEFINE_string(input, "", "Path to OpenLR file.");
DEFINE_string(output, "output.txt", "Path to output file");
+DEFINE_bool(assessment_output, false,
+ "Write an output in a format sutable for the assessment tool."
+ "Stick to the spark oriented format if set to false.");
DEFINE_string(non_matched_ids, "non-matched-ids.txt",
"Path to a file ids of non-matched segments will be saved to");
DEFINE_string(mwms_path, "", "Path to a folder with mwms.");
@@ -30,8 +45,9 @@ using namespace openlr;
namespace
{
-const int32_t kMinNumThreads = 1;
-const int32_t kMaxNumThreads = 128;
+int32_t const kMinNumThreads = 1;
+int32_t const kMaxNumThreads = 128;
+int32_t const kHandleAllSegments = -1;
void LoadIndexes(std::string const & pathToMWMFolder, std::vector<Index> & indexes)
{
@@ -120,6 +136,77 @@ bool const g_limitDummy = google::RegisterFlagValidator(&FLAGS_limit, &ValidateL
bool const g_numThreadsDummy =
google::RegisterFlagValidator(&FLAGS_num_threads, &ValidateNumThreads);
bool const g_mwmsPathDummy = google::RegisterFlagValidator(&FLAGS_mwms_path, &ValidataMwmPath);
+
+void SaveNonMatchedIds(std::string const & filename, std::vector<DecodedPath> const & paths)
+{
+ if (filename.empty())
+ return;
+
+ std::ofstream ofs(filename);
+ for (auto const & p : paths)
+ {
+ if (p.m_path.empty())
+ ofs << p.m_segmentId << endl;
+ }
+}
+
+std::vector<LinearSegment> LoadSegments(pugi::xml_document & document)
+{
+ std::vector<LinearSegment> segments;
+ if (!ParseOpenlr(document, segments))
+ {
+ LOG(LERROR, ("Can't parse data."));
+ exit(-1);
+ }
+
+ OpenLRSimpleDecoder::SegmentsFilter filter(FLAGS_ids_path, FLAGS_multipoints_only);
+ if (FLAGS_limit != kHandleAllSegments && FLAGS_limit >= 0 &&
+ static_cast<size_t>(FLAGS_limit) < segments.size())
+ {
+ segments.resize(FLAGS_limit);
+ }
+
+ my::EraseIf(segments,
+ [&filter](LinearSegment const & segment) { return !filter.Matches(segment); });
+
+ std::sort(segments.begin(), segments.end(), my::LessBy(&LinearSegment::m_segmentId));
+
+ return segments;
+}
+
+void WriteAssessmentFile(std::string const fileName, pugi::xml_document const & doc,
+ std::vector<DecodedPath> const & paths)
+{
+ if (fileName.empty())
+ return;
+
+ std::unordered_map<uint32_t, pugi::xml_node> xmlSegments;
+ for (auto const & xpathNode : doc.select_nodes("//reportSegments"))
+ {
+ auto const xmlSegment = xpathNode.node();
+ xmlSegments[xmlSegment.child("ReportSegmentID").text().as_uint()] = xmlSegment;
+ }
+
+ pugi::xml_document result;
+ for (auto const p : paths)
+ {
+ // TODO(mgsergio): Should we keep empty paths to assess them as well?
+ if (p.m_path.empty())
+ continue;
+
+ auto segment = result.append_child("Segment");
+ {
+ auto const xmlSegment = xmlSegments[p.m_segmentId.Get()];
+ segment.append_copy(xmlSegment);
+ }
+ {
+ auto node = segment.append_child("Route");
+ openlr::PathToXML(p.m_path, node);
+ }
+ }
+
+ result.save_file(fileName.data(), " " /* indent */);
+}
} // namespace
int main(int argc, char * argv[])
@@ -134,9 +221,26 @@ int main(int argc, char * argv[])
std::vector<Index> indexes(numThreads);
LoadIndexes(FLAGS_mwms_path, indexes);
- OpenLRSimpleDecoder::SegmentsFilter filter(FLAGS_ids_path, FLAGS_multipoints_only);
- OpenLRSimpleDecoder decoder(FLAGS_input, indexes);
- decoder.Decode(FLAGS_output, FLAGS_non_matched_ids, FLAGS_limit, filter, numThreads);
+ OpenLRSimpleDecoder decoder(indexes);
+
+ pugi::xml_document document;
+ auto const load_result = document.load_file(FLAGS_input.data());
+ if (!load_result)
+ {
+ LOG(LERROR, ("Can't load file", FLAGS_input, ":", load_result.description()));
+ exit(-1);
+ }
+
+ auto const segments = LoadSegments(document);
+
+ std::vector<DecodedPath> paths(segments.size());
+ decoder.Decode(segments, numThreads, paths);
+
+ SaveNonMatchedIds(FLAGS_non_matched_ids, paths);
+ if (FLAGS_assessment_output)
+ WriteAssessmentFile(FLAGS_output, document, paths);
+ else
+ WriteAsMappingForSpark(FLAGS_output, paths);
return 0;
}
diff --git a/openlr/openlr_tests/CMakeLists.txt b/openlr/openlr_tests/CMakeLists.txt
index 7a5bac649f..d32866c97a 100644
--- a/openlr/openlr_tests/CMakeLists.txt
+++ b/openlr/openlr_tests/CMakeLists.txt
@@ -2,15 +2,21 @@ project(openlr_tests)
set(
SRC
- openlr_sample_test.cpp
- )
+ decoded_path_test.cpp
+)
omim_add_test(${PROJECT_NAME} ${SRC})
omim_link_libraries(
${PROJECT_NAME}
+ generator_tests_support
+ platform_tests_support
+ generator
+ routing
+ search
openlr
indexer
+ routing_common
editor
platform_tests_support
platform
@@ -18,10 +24,12 @@ omim_link_libraries(
geometry
base
jansson
+ tess2
oauthcpp
opening_hours
pugixml
stats_client
+ succinct
protobuf
icu
${Qt5Core_LIBRARIES}
diff --git a/openlr/openlr_tests/decoded_path_test.cpp b/openlr/openlr_tests/decoded_path_test.cpp
new file mode 100644
index 0000000000..55f6820eff
--- /dev/null
+++ b/openlr/openlr_tests/decoded_path_test.cpp
@@ -0,0 +1,224 @@
+#include "testing/testing.hpp"
+
+#include "openlr/decoded_path.hpp"
+
+#include "generator/generator_tests_support/test_feature.hpp"
+#include "generator/generator_tests_support/test_mwm_builder.hpp"
+
+#include "indexer/classificator_loader.hpp"
+#include "indexer/index.hpp"
+
+#include "platform/country_file.hpp"
+#include "platform/local_country_file.hpp"
+#include "platform/platform.hpp"
+#include "platform/platform_tests_support/scoped_dir.hpp"
+#include "platform/platform_tests_support/scoped_file.hpp"
+
+#include "coding/file_name_utils.hpp"
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+#include <vector>
+
+#include "3party/pugixml/src/pugixml.hpp"
+#include "3party/pugixml/src/utils.hpp"
+
+using namespace generator::tests_support;
+using namespace platform::tests_support;
+using namespace platform;
+using namespace std;
+
+namespace
+{
+string const kTestDir = "openlr_decoded_path_test";
+string const kTestMwm = "test";
+
+double RoughUpToFive(double d)
+{
+ stringstream s;
+ s << setprecision(5) << fixed;
+ s << d;
+ s >> d;
+ return d;
+}
+
+m2::PointD RoughPoint(m2::PointD const & p) { return {RoughUpToFive(p.x), RoughUpToFive(p.y)}; }
+
+routing::Junction RoughJunction(routing::Junction const & j)
+{
+ return routing::Junction(RoughPoint(j.GetPoint()), j.GetAltitude());
+}
+
+routing::Edge RoughEdgeJunctions(routing::Edge const & e)
+{
+ return routing::Edge(e.GetFeatureId(), e.IsForward(), e.GetSegId(),
+ RoughJunction(e.GetStartJunction()), RoughJunction(e.GetEndJunction()));
+}
+
+void RoughJunctionsInPath(openlr::Path & p)
+{
+ for (auto & e : p)
+ e = RoughEdgeJunctions(e);
+}
+
+void TestSerializeDeserialize(openlr::Path const & path, Index const & index)
+{
+ pugi::xml_document doc;
+ openlr::PathToXML(path, doc);
+
+ openlr::Path restoredPath;
+ openlr::PathFromXML(doc, index, restoredPath);
+
+ // Fix MercatorBounds::From/ToLatLon floating point error
+ // for we could use TEST_EQUAL on result.
+ RoughJunctionsInPath(restoredPath);
+
+ TEST_EQUAL(path, restoredPath, ());
+}
+
+openlr::Path MakePath(FeatureType const & road, bool const forward)
+{
+ CHECK_EQUAL(road.GetFeatureType(), feature::GEOM_LINE, ());
+ CHECK_GREATER(road.GetPointsCount(), 0, ());
+ openlr::Path path;
+
+ size_t const maxPointIndex = road.GetPointsCount() - 1;
+ for (size_t i = 0; i < maxPointIndex; ++i)
+ {
+ size_t current{};
+ size_t next{};
+ if (forward)
+ {
+ current = i;
+ next = i + 1;
+ }
+ else
+ {
+ current = maxPointIndex - i;
+ next = current - 1;
+ }
+
+ auto const from = road.GetPoint(current);
+ auto const to = road.GetPoint(next);
+ path.emplace_back(road.GetID(), forward, current - static_cast<size_t>(!forward) /* segId */,
+ routing::Junction(from, 0 /* altitude */),
+ routing::Junction(to, 0 /* altitude */));
+ }
+
+ RoughJunctionsInPath(path);
+
+ return path;
+}
+
+template <typename Func>
+void WithRoad(vector<m2::PointD> const & points, Func && fn)
+{
+ classificator::Load();
+ auto & platform = GetPlatform();
+
+ auto const mwmPath = my::JoinPath(platform.WritableDir(), kTestDir);
+
+ LocalCountryFile country(mwmPath, CountryFile(kTestMwm), 0 /* version */);
+ ScopedDir testScopedDir(kTestDir);
+ ScopedFile testScopedMwm(mwmPath); // country.GetPath(MapOptions::Map));
+
+ TestMwmBuilder builder(country, feature::DataHeader::country);
+ builder.Add(TestRoad(points, "Interstate 60", "en"));
+
+ Index index;
+ auto const regResult = index.RegisterMap(country);
+ TEST_EQUAL(regResult.second, MwmSet::RegResult::Success, ());
+
+ MwmSet::MwmHandle mwmHandle = index.GetMwmHandleById(regResult.first);
+ TEST(mwmHandle.IsAlive(), ());
+
+ Index::FeaturesLoaderGuard const guard(index, regResult.first);
+ FeatureType road;
+ TEST(guard.GetFeatureByIndex(0, road), ());
+ road.ParseEverything();
+
+ fn(index, road);
+}
+
+UNIT_TEST(MakePath_Test)
+{
+ std::vector<m2::PointD> const points{{0, 0}, {0, 1}, {1, 0}, {1, 1}};
+ WithRoad(points, [&points](Index const & index, FeatureType & road) {
+ auto const & id = road.GetID();
+ {
+ openlr::Path const expected{{id,
+ true /* forward */,
+ 0 /* segId*/,
+ {points[0], 0 /* altitude */},
+ {points[1], 0 /* altitude */}},
+ {id,
+ true /* forward */,
+ 1 /* segId*/,
+ {points[1], 0 /* altitude */},
+ {points[2], 0 /* altitude */}},
+ {id,
+ true /* forward */,
+ 2 /* segId*/,
+ {points[2], 0 /* altitude */},
+ {points[3], 0 /* altitude */}}};
+ auto const path = MakePath(road, true /* forward */);
+ TEST_EQUAL(path, expected, ());
+ }
+ {
+ openlr::Path const expected{{id,
+ false /* forward */,
+ 2 /* segId*/,
+ {points[3], 0 /* altitude */},
+ {points[2], 0 /* altitude */}},
+ {id,
+ false /* forward */,
+ 1 /* segId*/,
+ {points[2], 0 /* altitude */},
+ {points[1], 0 /* altitude */}},
+ {id,
+ false /* forward */,
+ 0 /* segId*/,
+ {points[1], 0 /* altitude */},
+ {points[0], 0 /* altitude */}}};
+ {
+ auto const path = MakePath(road, false /* forward */);
+ TEST_EQUAL(path, expected, ());
+ }
+ }
+ });
+}
+
+UNIT_TEST(PathSerializeDeserialize_Test)
+{
+ WithRoad({{0, 0}, {0, 1}, {1, 0}, {1, 1}}, [](Index const & index, FeatureType & road) {
+ {
+ auto const path = MakePath(road, true /* forward */);
+ TestSerializeDeserialize(path, index);
+ }
+ {
+ auto const path = MakePath(road, false /* forward */);
+ TestSerializeDeserialize(path, index);
+ }
+ });
+}
+
+UNIT_TEST(GetPoints_Test)
+{
+ vector<m2::PointD> const points{{0, 0}, {0, 1}, {1, 0}, {1, 1}};
+ WithRoad(points, [&points](Index const &, FeatureType & road) {
+ {
+ auto path = MakePath(road, true /* forward */);
+ // RoughJunctionsInPath(path);
+ TEST_EQUAL(GetPoints(path), points, ());
+ }
+ {
+ auto path = MakePath(road, false /* forward */);
+ // RoughJunctionsInPath(path);
+ auto reversed = points;
+ reverse(begin(reversed), end(reversed));
+ TEST_EQUAL(GetPoints(path), reversed, ());
+ }
+ });
+}
+} // namespace
diff --git a/openlr/openlr_tests/openlr_sample_test.cpp b/openlr/openlr_tests/openlr_sample_test.cpp
deleted file mode 100644
index d4cdabf202..0000000000
--- a/openlr/openlr_tests/openlr_sample_test.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#include "testing/testing.hpp"
-
-#include "openlr/openlr_model.hpp"
-#include "openlr/openlr_sample.hpp"
-#include "openlr/openlr_model_xml.hpp"
-
-#include "indexer/index.hpp"
-
-#include "platform/platform_tests_support/scoped_file.hpp"
-
-#include "3party/pugixml/src/pugixml.hpp"
-
-using namespace openlr;
-
-UNIT_TEST(ParseOpenlr)
-{
- auto const openlrData = "<?xml version=\"1.0\"?>"
- " <Report dictionaryUpdateDateTime=\"2016-09-15T03:40:51\" dictionaryVersion=\"16.2\">"
- " <reportSegments>"
- " <ReportSegmentID>8446643</ReportSegmentID>"
- " <ReportSegmentLRC>"
- " <method>"
- " <olr:version>1.0</olr:version>"
- " <olr:locationReference>"
- " <olr:optionLinearLocationReference>"
- " <olr:first>"
- " <olr:coordinate>"
- " <olr:longitude>1738792</olr:longitude>"
- " <olr:latitude>2577486</olr:latitude>"
- " </olr:coordinate>"
- " <olr:lineProperties>"
- " <olr:frc olr:table=\"olr001_FunctionalRoadClass\" olr:code=\"6\"/>"
- " <olr:fow olr:table=\"olr002_FormOfWay\" olr:code=\"2\"/>"
- " <olr:bearing>"
- " <olr:value>8</olr:value>"
- " </olr:bearing>"
- " </olr:lineProperties>"
- " <olr:pathProperties>"
- " <olr:lfrcnp olr:table=\"olr001_FunctionalRoadClass\" olr:code=\"7\"/>"
- " <olr:dnp>"
- " <olr:value>3572</olr:value>"
- " </olr:dnp>"
- " <olr:againstDrivingDirection>true</olr:againstDrivingDirection>"
- " </olr:pathProperties>"
- " </olr:first>"
- " <olr:last>"
- " <olr:coordinate>"
- " <olr:longitude>-1511</olr:longitude>"
- " <olr:latitude>2858</olr:latitude>"
- " </olr:coordinate>"
- " <olr:lineProperties>"
- " <olr:frc olr:table=\"olr001_FunctionalRoadClass\" olr:code=\"7\"/>"
- " <olr:fow olr:table=\"olr002_FormOfWay\" olr:code=\"3\"/>"
- " <olr:bearing>"
- " <olr:value>105</olr:value>"
- " </olr:bearing>"
- " </olr:lineProperties>"
- " </olr:last>"
- " <olr:positiveOffset>"
- " <olr:value>1637</olr:value>"
- " </olr:positiveOffset>"
- " <olr:negativeOffset>"
- " <olr:value>919</olr:value>"
- " </olr:negativeOffset>"
- " </olr:optionLinearLocationReference>"
- " </olr:locationReference>"
- " </method>"
- " </ReportSegmentLRC>"
- " <LinearConnectivity>"
- " <negLink>"
- " <ReportSegmentID>8446642</ReportSegmentID>"
- " </negLink>"
- " <posLink>"
- " <ReportSegmentID>91840286</ReportSegmentID>"
- " </posLink>"
- " </LinearConnectivity>"
- " <segmentLength>1018</segmentLength>"
- " <segmentRefSpeed>0</segmentRefSpeed>"
- " </reportSegments>";
-
- vector<openlr::LinearSegment> segments;
- pugi::xml_document doc;
- TEST_EQUAL(doc.load(openlrData), pugi::xml_parse_status::status_ok, ());
- TEST(openlr::ParseOpenlr(doc, segments), ());
-
- TEST_EQUAL(segments.size(), 1, ());
-
- auto const & segment = segments.front();
- TEST_EQUAL(segment.m_segmentId, 8446643, ());
- TEST_EQUAL(segment.m_segmentLengthMeters, 1018, ());
-
- auto const locRef = segment.m_locationReference;
- TEST_EQUAL(locRef.m_points.size(), 2, ());
-
- auto const firstPoint = locRef.m_points.front();
- auto expectedLatLon = ms::LatLon{55.30683, 37.31041};
- TEST(firstPoint.m_latLon.EqualDxDy(expectedLatLon, 1e-5), (firstPoint.m_latLon, "!=", expectedLatLon));
- TEST_EQUAL(firstPoint.m_bearing, 8, ());
- TEST(firstPoint.m_formOfWay == openlr::FormOfWay::MultipleCarriageway,
- ("Wrong form of a way."));
- TEST(firstPoint.m_functionalRoadClass == openlr::FunctionalRoadClass::FRC6,
- ("Wrong functional road class."));
- TEST_EQUAL(firstPoint.m_distanceToNextPoint, 3572, ());
- TEST(firstPoint.m_lfrcnp == openlr::FunctionalRoadClass::FRC7, ("Wrong functional road class."));
- TEST_EQUAL(firstPoint.m_againstDrivingDirection, true, ());
-
- auto const secondPoint = locRef.m_points.back();
- expectedLatLon = ms::LatLon{55.33541, 37.29530};
- TEST(secondPoint.m_latLon.EqualDxDy(expectedLatLon, 1e-5), (secondPoint.m_latLon, "!=", expectedLatLon));
- TEST_EQUAL(secondPoint.m_bearing, 105, ());
- TEST(secondPoint.m_formOfWay == openlr::FormOfWay::SingleCarriageway, ("Wrong form of way."));
- TEST(secondPoint.m_functionalRoadClass == openlr::FunctionalRoadClass::FRC7,
- ("Wrong functional road class."));
-
- TEST_EQUAL(locRef.m_positiveOffsetMeters, 1637, ());
- TEST_EQUAL(locRef.m_negativeOffsetMeters, 919, ());
-}
-
-UNIT_TEST(LoadSamplePool_Test)
-{
- platform::tests_support::ScopedFile sample(
- "sample.txt",
- "8442794\tRussia_Moscow Oblast_East-36328-0-fwd-58.3775=Russia_Moscow Oblast_East-36328-1-fwd-14.0846\n"
- "8442817\tRussia_Moscow Oblast_East-36324-11-bwd-101.362=Russia_Moscow Oblast_East-36324-10-bwd-48.2464=Russia_Moscow Oblast_East-36324-9-bwd-92.06\n"
- "8442983\tRussia_Moscow Oblast_East-45559-1-bwd-614.231=Russia_Moscow Oblast_East-45559-0-bwd-238.259\n"
- "8442988\tRussia_Moscow Oblast_East-36341-3-bwd-81.3394\n");
-
- Index emptyIndex; // Empty is ok for this test.
- auto const pool = LoadSamplePool(sample.GetFullPath(), emptyIndex);
-
- TEST_EQUAL(pool.size(), 4, ());
-
- TEST(pool[0].m_evaluation == openlr::ItemEvaluation::Unevaluated,
- ("pool[0].m_evaluation != openlr::ItemEvaluation::Unevaluated"));
- TEST_EQUAL(pool[0].m_partnerSegmentId.Get(), 8442794, ());
- TEST_EQUAL(pool[1].m_partnerSegmentId.Get(), 8442817, ());
- TEST_EQUAL(pool[2].m_partnerSegmentId.Get(), 8442983, ());
-
- TEST_EQUAL(pool[0].m_segments.size(), 2, ());
- TEST_EQUAL(pool[1].m_segments.size(), 3, ());
- TEST_EQUAL(pool[2].m_segments.size(), 2, ());
-
- TEST_EQUAL(pool[0].m_segments[0].m_segId, 0, ());
- TEST_EQUAL(pool[1].m_segments[0].m_segId, 11, ());
- TEST_EQUAL(pool[2].m_segments[0].m_segId, 1, ());
-
- TEST(pool[0].m_segments[0].m_isForward, ());
- TEST(!pool[1].m_segments[0].m_isForward, ());
- TEST(!pool[2].m_segments[0].m_isForward, ());
-}
diff --git a/openlr/openlr_tests/openlr_tests.pro b/openlr/openlr_tests/openlr_tests.pro
index 3f1a7e9426..9705b2b929 100644
--- a/openlr/openlr_tests/openlr_tests.pro
+++ b/openlr/openlr_tests/openlr_tests.pro
@@ -4,8 +4,30 @@ CONFIG -= app_bundle
TEMPLATE = app
ROOT_DIR = ../..
-DEPENDENCIES = routing routing_common search storage indexer editor platform_tests_support platform \
- geometry coding base protobuf osrm stats_client pugixml openlr jansson succinct icu
+DEPENDENCIES = \
+ generator_tests_support \
+ platform_tests_support \
+ generator \
+ routing \
+ routing_common \
+ search \
+ storage \
+ indexer \
+ editor \
+ platform_tests_support \
+ platform \
+ geometry \
+ coding \
+ base \
+ protobuf \
+ tess2 \
+ osrm \
+ stats_client \
+ pugixml \
+ openlr \
+ jansson \
+ succinct \
+ icu \
include($$ROOT_DIR/common.pri)
@@ -19,4 +41,4 @@ HEADERS += \
SOURCES += \
$$ROOT_DIR/testing/testingmain.cpp \
- openlr_sample_test.cpp \
+ decoded_path_test.cpp \