Add possibility to mark a path as ignored.

This commit is contained in:
Sergey Magidovich 2017-08-17 16:17:11 +03:00 committed by Yuri Gorshenin
parent 7a2464a007
commit 331632c3b5
4 changed files with 115 additions and 60 deletions

View file

@ -274,12 +274,19 @@ MainWindow::MainWindow(Framework & framework)
m_mapWidget->SetMode(MapWidget::Mode::Normal);
},
QKeySequence("Ctrl+R"));
m_ignorePathAction = fileMenu->addAction("Ignore path",
[this] {
m_trafficMode->IgnorePath();
m_mapWidget->SetMode(MapWidget::Mode::Normal);
},
QKeySequence("Ctrl+I"));
m_closeTrafficSampleAction->setEnabled(false /* enabled */);
m_saveTrafficSampleAction->setEnabled(false /* enabled */);
m_startEditingAction->setEnabled(false /* enabled */);
m_commitPathAction->setEnabled(false /* enabled */);
m_cancelPathAction->setEnabled(false /* enabled */);
m_ignorePathAction->setEnabled(false /* enabled */);
}
void MainWindow::CreateTrafficPanel(string const & dataFilePath)
@ -336,6 +343,7 @@ void MainWindow::OnOpenTrafficSample()
m_closeTrafficSampleAction->setEnabled(true /* enabled */);
m_saveTrafficSampleAction->setEnabled(true /* enabled */);
m_startEditingAction->setEnabled(true /* enabled */);
m_ignorePathAction->setEnabled(true /* enabled */);
}
void MainWindow::OnCloseTrafficSample()
@ -349,6 +357,7 @@ void MainWindow::OnCloseTrafficSample()
m_startEditingAction->setEnabled(false /* enabled */);
m_commitPathAction->setEnabled(false /* enabled */);
m_cancelPathAction->setEnabled(false /* enabled */);
m_ignorePathAction->setEnabled(false /* enabled */);
DestroyTrafficPanel();
}
@ -372,4 +381,5 @@ void MainWindow::OnPathEditingStop()
{
m_commitPathAction->setEnabled(false /* enabled */);
m_cancelPathAction->setEnabled(false /* enabled */);
m_cancelPathAction->setEnabled(false /* enabled */);
}

View file

@ -45,6 +45,7 @@ private:
QAction * m_startEditingAction = nullptr;
QAction * m_commitPathAction = nullptr;
QAction * m_cancelPathAction = nullptr;
QAction * m_ignorePathAction = nullptr;
MapWidget * m_mapWidget = nullptr;
};

View file

@ -120,37 +120,31 @@ TrafficMode::TrafficMode(std::string const & dataFileName,
{
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.
auto const partnerSegment = xmlSegment.child("reportSegments");
if (!openlr::SegmentFromXML(partnerSegment, segment.GetPartnerSegment()))
MYTHROW(TrafficModeError, ("An error occured while parsing: can't parse segment"));
openlr::Path matchedPath;
openlr::Path fakePath;
openlr::Path goldenPath;
segment.SetPartnerXML(partnerSegment);
}
openlr::LinearSegment segment;
// TODO(mgsergio): Unify error handling interface of openlr_xml_mode and decoded_path parsers.
auto const partnerSegmentXML = xmlSegment.child("reportSegments");
if (!openlr::SegmentFromXML(partnerSegmentXML, segment))
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);
}
openlr::PathFromXML(route, m_index, matchedPath);
if (auto const route = xmlSegment.child("FakeRoute"))
{
auto & path = segment.GetFakePath();
path.emplace();
openlr::PathFromXML(route, m_index, *path);
}
openlr::PathFromXML(route, m_index, fakePath);
if (auto const route = xmlSegment.child("GoldenRoute"))
openlr::PathFromXML(route, m_index, goldenPath);
m_segments.emplace_back(segment, matchedPath, fakePath, goldenPath, partnerSegmentXML);
if (auto const status = xmlSegment.child("Ignored"))
{
auto & path = segment.GetGoldenPath();
path.emplace();
openlr::PathFromXML(route, m_index, *path);
if (status.text().as_bool())
m_segments.back().Ignore();
}
}
}
@ -174,20 +168,24 @@ bool TrafficMode::SaveSampleAs(std::string const & fileName) const
auto segment = result.append_child("Segment");
segment.append_copy(sc.GetPartnerXMLSegment());
if (auto const & path = sc.GetMatchedPath())
if (sc.GetStatus() == SegmentCorrespondence::Status::Ignored)
{
result.append_child("Ignored").text() = true;
}
if (!sc.GetMatchedPath().empty())
{
auto node = segment.append_child("Route");
openlr::PathToXML(*path, node);
openlr::PathToXML(sc.GetMatchedPath(), node);
}
if (auto const & path = sc.GetFakePath())
if (!sc.GetFakePath().empty())
{
auto node = segment.append_child("FakeRoute");
openlr::PathToXML(*path, node);
openlr::PathToXML(sc.GetFakePath(), node);
}
if (auto const & path = sc.GetGoldenPath())
if (!sc.GetGoldenPath().empty())
{
auto node = segment.append_child("GoldenRoute");
openlr::PathToXML(*path, node);
openlr::PathToXML(sc.GetGoldenPath(), node);
}
}
@ -236,10 +234,10 @@ void TrafficMode::OnItemSelected(QItemSelection const & selected, QItemSelection
// TODO(mgsergio): Use a better way to set viewport and scale.
m_drawerDelegate->SetViewportCenter(viewportCenter);
m_drawerDelegate->DrawEncodedSegment(partnerSegment);
if (auto const & path = m_currentSegment->GetMatchedPath())
m_drawerDelegate->DrawDecodedSegments(GetPoints(*path));
if (auto const & path = m_currentSegment->GetGoldenPath())
m_drawerDelegate->DrawGoldenPath(GetPoints(*path));
if (!m_currentSegment->GetMatchedPath().empty())
m_drawerDelegate->DrawDecodedSegments(GetPoints(m_currentSegment->GetMatchedPath()));
if (!m_currentSegment->GetGoldenPath().empty())
m_drawerDelegate->DrawGoldenPath(GetPoints(m_currentSegment->GetGoldenPath()));
}
Qt::ItemFlags TrafficMode::flags(QModelIndex const & index) const
@ -257,7 +255,7 @@ void TrafficMode::StartBuildingPath()
if (m_buildingPath)
MYTHROW(TrafficModeError, ("Path building already in progress."));
if (m_currentSegment->GetGoldenPath())
if (!m_currentSegment->GetGoldenPath().empty())
{
auto const btn = QMessageBox::question(
nullptr,
@ -267,7 +265,7 @@ void TrafficMode::StartBuildingPath()
return;
}
m_currentSegment->GetGoldenPath() = boost::none;
m_currentSegment->SetGoldenPath({});
m_buildingPath = true;
m_drawerDelegate->ClearGoldenPath();
@ -337,30 +335,52 @@ void TrafficMode::CommitPath()
);
}
m_currentSegment->GetGoldenPath() = path;
m_currentSegment->SetGoldenPath(path);
m_goldenPath.clear();
}
void TrafficMode::RollBackPath()
{
CHECK(m_currentSegment, ("No segments selected"));
// TODO(mgsergio): CHECK ?
if (!m_buildingPath)
MYTHROW(TrafficModeError, ("No path building is in progress."));
CHECK(m_buildingPath, ("No path building is in progress."));
m_buildingPath = false;
// TODO(mgsergio): Add a method for common visual manipulations.
m_drawerDelegate->ClearAllVisualizedPoints();
m_drawerDelegate->ClearGoldenPath();
if (auto const & path = m_currentSegment->GetGoldenPath())
m_drawerDelegate->DrawGoldenPath(GetPoints(*path));
if (!m_currentSegment->GetGoldenPath().empty())
m_drawerDelegate->DrawGoldenPath(GetPoints(m_currentSegment->GetGoldenPath()));
m_goldenPath.clear();
emit EditingStopped();
}
void TrafficMode::IgnorePath()
{
CHECK(m_currentSegment, ("No segments selected"));
if (!m_currentSegment->GetGoldenPath().empty())
{
auto const btn = QMessageBox::question(
nullptr,
"Override warning",
"The selected segment has a golden path. Do you want to discard it?");
if (btn == QMessageBox::No)
return;
}
m_buildingPath = false;
// TODO(mgsergio): Add a method for common visual manipulations.
m_drawerDelegate->ClearAllVisualizedPoints();
m_drawerDelegate->ClearGoldenPath();
m_currentSegment->Ignore();
m_goldenPath.clear();
emit EditingStopped();
}
size_t TrafficMode::GetPointsCount() const
{
return m_goldenPath.size();

View file

@ -15,8 +15,6 @@
#include <unordered_map>
#include <utility>
#include <boost/optional.hpp>
#include <QAbstractTableModel>
#include <Qt>
@ -59,7 +57,12 @@ private:
class SegmentCorrespondence
{
public:
SegmentCorrespondence() = default;
enum class Status
{
Untouched,
Assessed,
Ignored
};
SegmentCorrespondence(SegmentCorrespondence const & sc)
{
@ -71,37 +74,55 @@ public:
m_partnerXMLDoc.reset(sc.m_partnerXMLDoc);
m_partnerXMLSegment = m_partnerXMLDoc.child("reportSegments");
m_status = sc.m_status;
}
boost::optional<openlr::Path> const & GetMatchedPath() const { return m_matchedPath; }
boost::optional<openlr::Path> & GetMatchedPath() { return m_matchedPath; }
SegmentCorrespondence(openlr::LinearSegment const & segment,
openlr::Path const & matchedPath,
openlr::Path const & fakePath,
openlr::Path const & goldenPath,
pugi::xml_node const & partnerSegmentXML) : m_partnerSegment(segment)
, m_matchedPath(matchedPath)
, m_fakePath(fakePath)
{
SetGoldenPath(goldenPath);
boost::optional<openlr::Path> const & GetFakePath() const { return m_fakePath; }
boost::optional<openlr::Path> & GetFakePath() { return m_fakePath; }
m_partnerXMLDoc.append_copy(partnerSegmentXML);
m_partnerXMLSegment = m_partnerXMLDoc.child("reportSegments");
CHECK(m_partnerXMLSegment, ("Node should contain <reportSegments> part"));
}
boost::optional<openlr::Path> const & GetGoldenPath() const { return m_goldenPath; }
boost::optional<openlr::Path> & GetGoldenPath() { return m_goldenPath; }
openlr::Path const & GetMatchedPath() const { return m_matchedPath; }
openlr::Path const & GetFakePath() const { return m_fakePath; }
openlr::Path const & GetGoldenPath() const { return m_goldenPath; }
void SetGoldenPath(openlr::Path const & p) {
m_goldenPath = p;
m_status = p.empty() ? Status::Untouched : Status::Assessed;
}
openlr::LinearSegment const & GetPartnerSegment() const { return m_partnerSegment; }
openlr::LinearSegment & GetPartnerSegment() { return m_partnerSegment; }
uint32_t GetPartnerSegmentId() const { return m_partnerSegment.m_segmentId; }
pugi::xml_document const & GetPartnerXML() const { return m_partnerXMLDoc; }
pugi::xml_node const & GetPartnerXMLSegment() const { return m_partnerXMLSegment; }
void SetPartnerXML(pugi::xml_node const & n)
Status GetStatus() const { return m_status; }
void Ignore()
{
m_partnerXMLDoc.append_copy(n);
m_partnerXMLSegment = m_partnerXMLDoc.child("reportSegments");
CHECK(m_partnerXMLSegment, ("Node should contain <reportSegments> part"));
m_status = Status::Ignored;
m_goldenPath.clear();
}
private:
openlr::LinearSegment m_partnerSegment;
// TODO(mgsergio): Maybe get rid of boost::optional and rely on emptiness of the path instead?
boost::optional<openlr::Path> m_matchedPath;
boost::optional<openlr::Path> m_fakePath;
boost::optional<openlr::Path> m_goldenPath;
openlr::Path m_matchedPath;
openlr::Path m_fakePath;
openlr::Path m_goldenPath;
// A dirty hack to save back SegmentCorrespondence.
// TODO(mgsergio): Consider unifying xml serialization with one used in openlr_stat.
@ -109,6 +130,8 @@ private:
// This is used by GetPartnerXMLSegment shortcut to return const ref. pugi::xml_node is
// just a wrapper so returning by value won't guarantee constness.
pugi::xml_node m_partnerXMLSegment;
Status m_status = Status::Untouched;
};
/// This class is used to delegate segments drawing to the DrapeEngine.
@ -188,6 +211,7 @@ public:
void PopPoint();
void CommitPath();
void RollBackPath();
void IgnorePath();
size_t GetPointsCount() const;
m2::PointD const & GetPoint(size_t const index) const;