forked from organicmaps/organicmaps
Add possibility to mark a path as ignored.
This commit is contained in:
parent
7a2464a007
commit
331632c3b5
4 changed files with 115 additions and 60 deletions
|
@ -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 */);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue