diff --git a/3party/pugixml/src/utils.hpp b/3party/pugixml/src/utils.hpp index f76010daf8..fda74742fa 100644 --- a/3party/pugixml/src/utils.hpp +++ b/3party/pugixml/src/utils.hpp @@ -13,4 +13,14 @@ inline std::string XMLToString(pugi::xml_node const & n, Args &&... args) n.print(sstr, std::forward(args)...); return sstr.str(); } + +inline std::string DebugPrint(pugi::xml_node const & n) +{ + return XMLToString(n); } + +inline std::string DebugPrint(pugi::xml_document const & n) +{ + return DebugPrint(dynamic_cast(n)); +} +} // namespace pugi diff --git a/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp b/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp index 0bea67ff6f..e201cfb476 100644 --- a/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp +++ b/openlr/openlr_match_quality/openlr_assessment_tool/mainwindow.cpp @@ -32,6 +32,10 @@ namespace { class TrafficDrawerDelegate : public TrafficDrawerDelegateBase { + static auto constexpr kEncodedLineId = "encodedPath"; + static auto constexpr kDecodedLineId = "decodedPath"; + static auto constexpr kGoldenLineId = "goldenPath"; + public: TrafficDrawerDelegate(Framework & framework) : m_framework(framework) @@ -50,7 +54,7 @@ public: CHECK(!points.empty(), ("Points must not be empty.")); LOG(LINFO, ("Decoded segment", points)); - m_drapeApi.AddLine(NextLineId(), + m_drapeApi.AddLine(kDecodedLineId, df::DrapeApiLineData(points, dp::Color(0, 0, 255, 255)) .Width(3.0f).ShowPoints(true /* markPoints */)); } @@ -58,24 +62,28 @@ public: void DrawEncodedSegment(std::vector const & points) override { LOG(LINFO, ("Encoded segment", points)); - m_drapeApi.AddLine(NextLineId(), + m_drapeApi.AddLine(kEncodedLineId, df::DrapeApiLineData(points, dp::Color(255, 0, 0, 255)) .Width(3.0f).ShowPoints(true /* markPoints */)); } + void DrawGoldenPath(std::vector const & points) override + { + m_drapeApi.AddLine(kGoldenLineId, + df::DrapeApiLineData(points, dp::Color(255, 127, 36, 255)) + .Width(4.0f).ShowPoints(true /* markPoints */)); + } + + void ClearGoldenPath() override + { + m_drapeApi.RemoveLine(kGoldenLineId); + } + void ClearAllPaths() override { m_drapeApi.Clear(); } - void VisualizeGoldenPath(std::vector const & points) override - { - ClearAllPaths(); - - m_drapeApi.AddLine(NextLineId(), - df::DrapeApiLineData(points, dp::Color(255, 127, 36, 255)) - .Width(4.0f).ShowPoints(true /* markPoints */)); - } void VisualizePoints(std::vector const & points) override { @@ -86,17 +94,13 @@ public: g.m_controller.CreateUserMark(p); } - void CleanAllVisualizedPoints() override + void ClearAllVisualizedPoints() override { UserMarkControllerGuard g(m_bm, UserMarkType::DEBUG_MARK); g.m_controller.Clear(); } private: - string NextLineId() { return strings::to_string(m_lineId++); } - - uint32_t m_lineId = 0; - Framework & m_framework; df::DrapeApi & m_drapeApi; BookmarkManager & m_bm; @@ -202,7 +206,7 @@ public: return ClickType::Remove; for (auto const & p : reachablePoints) { - if (PointsMatch(clickPoint, p)); + if (PointsMatch(clickPoint, p)) return ClickType::Add; } return ClickType::Miss; 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 59e0b0457a..9767ef2b8e 100644 --- a/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp +++ b/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.cpp @@ -5,7 +5,10 @@ #include "indexer/index.hpp" #include "indexer/scales.hpp" +#include "3party/pugixml/src/utils.hpp" + #include +#include #include @@ -141,13 +144,18 @@ TrafficMode::TrafficMode(std::string const & dataFileName, 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); } + if (auto const route = xmlSegment.child("GoldenRoute")) + { + auto & path = segment.GetGoldenPath(); + path.emplace(); + openlr::PathFromXML(route, m_index, *path); + } } } catch (openlr::DecodedPathLoadError const & e) @@ -167,7 +175,8 @@ bool TrafficMode::SaveSampleAs(std::string const & fileName) const for (auto const & sc : m_segments) { auto segment = result.append_child("Segment"); - segment.append_copy(sc.GetPartnerXML()); + segment.append_copy(sc.GetPartnerXMLSegment()); + if (auto const & path = sc.GetMatchedPath()) { auto node = segment.append_child("Route"); @@ -236,6 +245,8 @@ void TrafficMode::OnItemSelected(QItemSelection const & selected, QItemSelection m_drawerDelegate->SetViewportCenter(GetStart(firstEdge)); m_drawerDelegate->DrawEncodedSegment(GetPoints(m_currentSegment->GetPartnerSegment())); m_drawerDelegate->DrawDecodedSegments(GetPoints(path)); + if (auto const & path = m_currentSegment->GetGoldenPath()) + m_drawerDelegate->DrawGoldenPath(GetPoints(*path)); } Qt::ItemFlags TrafficMode::flags(QModelIndex const & index) const @@ -248,9 +259,25 @@ Qt::ItemFlags TrafficMode::flags(QModelIndex const & index) const void TrafficMode::StartBuildingPath() { + CHECK(m_currentSegment, ("A segment should be selected before path building is started.")); + if (m_buildingPath) MYTHROW(TrafficModeError, ("Path building already in progress.")); + + if (m_currentSegment->GetGoldenPath()) + { + auto const btn = QMessageBox::question( + nullptr, + "Override warning", + "The selected segment already have a golden path. Do you want to override?"); + if (btn == QMessageBox::No) + return; + } + + m_currentSegment->GetGoldenPath() = boost::none; + m_buildingPath = true; + m_drawerDelegate->ClearGoldenPath(); m_drawerDelegate->VisualizePoints( m_pointsDelegate->GetAllJunctionPointsInViewPort()); } @@ -278,6 +305,9 @@ void TrafficMode::CommitPath() if (!m_buildingPath) MYTHROW(TrafficModeError, ("Path building is not started")); + m_buildingPath = false; + m_drawerDelegate->ClearAllVisualizedPoints(); + if (m_goldenPath.empty()) { LOG(LDEBUG, ("Golden path is empty :'(")); @@ -315,11 +345,23 @@ void TrafficMode::CommitPath() } m_currentSegment->GetGoldenPath() = path; - m_buildingPath = false; } void TrafficMode::RollBackPath() { + CHECK(m_currentSegment, ("No segments selected")); + + // TODO(mgsergio): CHECK ? + if (!m_buildingPath) + MYTHROW(TrafficModeError, ("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)); } size_t TrafficMode::GetPointsCount() const @@ -349,6 +391,9 @@ std::vector TrafficMode::GetCoordinates() const // TODO(mgsergio): Draw the first point when the path size is 1. void TrafficMode::HandlePoint(m2::PointD clickPoint, Qt::MouseButton const button) { + if (!m_buildingPath) + return; + auto const currentPathLength = GetPointsCount(); auto const lastClickedPoint = currentPathLength != 0 ? GetLastPoint() @@ -388,19 +433,18 @@ void TrafficMode::HandlePoint(m2::PointD clickPoint, Qt::MouseButton const butto return p.EqualDxDy(lastClickedPoint, 1e-6); }), end(reachablePoints)); - m_drawerDelegate->VisualizeGoldenPath(GetCoordinates()); + m_drawerDelegate->DrawGoldenPath(GetCoordinates()); } - m_drawerDelegate->CleanAllVisualizedPoints(); + m_drawerDelegate->ClearAllVisualizedPoints(); m_drawerDelegate->VisualizePoints(reachablePoints); m_drawerDelegate->VisualizePoints({clickPoint}); break; case ClickType::Remove: // TODO(mgsergio): Rename this case. if (button == Qt::MouseButton::LeftButton) // RemovePoint { - m_drawerDelegate->CleanAllVisualizedPoints(); - // TODO(mgsergio): Remove only golden path. - m_drawerDelegate->ClearAllPaths(); + m_drawerDelegate->ClearAllVisualizedPoints(); + m_drawerDelegate->ClearGoldenPath(); PopPoint(); if (m_goldenPath.empty()) @@ -418,7 +462,7 @@ void TrafficMode::HandlePoint(m2::PointD clickPoint, Qt::MouseButton const butto } if (GetPointsCount() > 1) - m_drawerDelegate->VisualizeGoldenPath(GetCoordinates()); + m_drawerDelegate->DrawGoldenPath(GetCoordinates()); } else if (button == Qt::MouseButton::RightButton) { 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 ff63e140e0..a5be7bddbe 100644 --- a/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp +++ b/openlr/openlr_match_quality/openlr_assessment_tool/traffic_mode.hpp @@ -68,7 +68,8 @@ public: m_fakePath = sc.m_fakePath; m_goldenPath = sc.m_goldenPath; - m_partnerXMLSegment.reset(sc.m_partnerXMLSegment); + m_partnerXMLDoc.reset(sc.m_partnerXMLDoc); + m_partnerXMLSegment = m_partnerXMLDoc.child("reportSegments"); } boost::optional const & GetMatchedPath() const { return m_matchedPath; } @@ -85,8 +86,14 @@ public: uint32_t GetPartnerSegmentId() const { return m_partnerSegment.m_segmentId; } - pugi::xml_document const & GetPartnerXML() const { return m_partnerXMLSegment; } - void SetPartnerXML(pugi::xml_node const & n) { m_partnerXMLSegment.append_copy(n); } + 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) + { + m_partnerXMLDoc.append_copy(n); + m_partnerXMLSegment = m_partnerXMLDoc.child("reportSegments"); + CHECK(m_partnerXMLSegment, ("Node should contain part")); + } private: openlr::LinearSegment m_partnerSegment; @@ -97,7 +104,10 @@ private: // A dirty hack to save back SegmentCorrespondence. // TODO(mgsergio): Consider unifying xml serialization with one used in openlr_stat. - pugi::xml_document m_partnerXMLSegment; + pugi::xml_document m_partnerXMLDoc; + // 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; }; /// This class is used to delegate segments drawing to the DrapeEngine. @@ -110,12 +120,13 @@ public: virtual void DrawDecodedSegments(std::vector const & points) = 0; virtual void DrawEncodedSegment(std::vector const & points) = 0; + virtual void DrawGoldenPath(std::vector const & points) = 0; + + virtual void ClearGoldenPath() = 0; virtual void ClearAllPaths() = 0; - virtual void VisualizeGoldenPath(std::vector const & points) = 0; - virtual void VisualizePoints(std::vector const & points) = 0; - virtual void CleanAllVisualizedPoints() = 0; + virtual void ClearAllVisualizedPoints() = 0; }; class BookmarkManager;