From 121bdc3720b7eccff21b3b8fff6fe0a333d50ca3 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Fri, 2 Dec 2016 15:31:22 +0300 Subject: [PATCH] Tuned two-way roads offsets --- drape_frontend/frontend_renderer.cpp | 3 +- drape_frontend/rule_drawer.cpp | 67 ++++++++++++++++++++++------ drape_frontend/traffic_generator.cpp | 17 +++---- drape_frontend/traffic_renderer.cpp | 42 +++++++++++------ drape_frontend/traffic_renderer.hpp | 2 + geometry/polyline2d.hpp | 8 ++-- 6 files changed, 99 insertions(+), 40 deletions(-) diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 3d282d63f2..8bb7f8abc4 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1218,10 +1218,9 @@ void FrontendRenderer::RenderTrafficAndRouteLayer(ScreenBase const & modelView) { if (m_trafficRenderer->HasRenderData()) { - float const opacity = (m_routeRenderer->GetRouteData() != nullptr) ? 0.5f : 1.0f; GLFunctions::glClearDepth(); GLFunctions::glEnable(gl_const::GLDepthTest); - m_trafficRenderer->RenderTraffic(modelView, m_currentZoomLevel, opacity, + m_trafficRenderer->RenderTraffic(modelView, m_currentZoomLevel, 1.0f /* opacity */, make_ref(m_gpuProgramManager), m_generalUniforms); } diff --git a/drape_frontend/rule_drawer.cpp b/drape_frontend/rule_drawer.cpp index 5f8b7697a7..9913e77fa0 100644 --- a/drape_frontend/rule_drawer.cpp +++ b/drape_frontend/rule_drawer.cpp @@ -3,6 +3,7 @@ #include "drape_frontend/apply_feature_functors.hpp" #include "drape_frontend/engine_context.hpp" #include "drape_frontend/stylist.hpp" +#include "drape_frontend/traffic_renderer.hpp" #include "drape_frontend/visual_params.hpp" #include "indexer/feature.hpp" @@ -42,29 +43,57 @@ df::BaseApplyFeature::HotelData ExtractHotelData(FeatureType const & f) return result; } -void ExtractTrafficGeometry(FeatureType const & f, df::RoadClass const & roadClass, m2::PolylineD const & polyline, - df::TrafficSegmentsGeometry & geometry) +void ExtractTrafficGeometry(FeatureType const & f, df::RoadClass const & roadClass, + m2::PolylineD const & polyline, bool oneWay, int zoomLevel, + double pixelToGraphics, df::TrafficSegmentsGeometry & geometry) { - df::TrafficSegmentsGeometry output; if (polyline.GetSize() < 2) return; - bool const isLeftHandTraffic = f.GetID().m_mwmId.GetInfo()->GetRegionData().Get(feature::RegionData::RD_DRIVING) == "l"; + auto const & regionData = f.GetID().m_mwmId.GetInfo()->GetRegionData(); + bool const isLeftHandTraffic = regionData.Get(feature::RegionData::RD_DRIVING) == "l"; + + // Calculate road offset for two-way roads. The offset is available since a zoom level in + // kMinOffsetZoomLevels. + double twoWayOffset = 0.0; + double const kOffsetScalar = 0.5 * df::VisualParams::Instance().GetVisualScale(); + static vector const kMinOffsetZoomLevels = { 13, 11, 10 }; + bool const needTwoWayOffset = !oneWay && zoomLevel > kMinOffsetZoomLevels[static_cast(roadClass)]; + if (needTwoWayOffset) + twoWayOffset = kOffsetScalar * pixelToGraphics * df::TrafficRenderer::GetPixelWidth(roadClass, zoomLevel); static vector directions = {traffic::TrafficInfo::RoadSegmentId::kForwardDirection, traffic::TrafficInfo::RoadSegmentId::kReverseDirection}; auto & segments = geometry[f.GetID().m_mwmId]; segments.reserve(segments.size() + directions.size() * (polyline.GetSize() - 1)); - for (uint16_t segmentIndex = 0; segmentIndex + 1 < static_cast(polyline.GetSize()); ++segmentIndex) + for (uint16_t segIndex = 0; segIndex + 1 < static_cast(polyline.GetSize()); ++segIndex) { for (size_t dirIndex = 0; dirIndex < directions.size(); ++dirIndex) { - auto const sid = traffic::TrafficInfo::RoadSegmentId(f.GetID().m_index, segmentIndex, directions[dirIndex]); + if (oneWay && dirIndex > 0) + break; + + auto const sid = traffic::TrafficInfo::RoadSegmentId(f.GetID().m_index, segIndex, directions[dirIndex]); bool isReversed = (directions[dirIndex] == traffic::TrafficInfo::RoadSegmentId::kReverseDirection); if (isLeftHandTraffic) isReversed = !isReversed; - segments.emplace_back(sid, df::TrafficSegmentGeometry(polyline.ExtractSegment(segmentIndex, isReversed), roadClass)); + auto const segment = polyline.ExtractSegment(segIndex, isReversed); + ASSERT_EQUAL(segment.size(), 2, ()); + if (needTwoWayOffset) + { + m2::PointD const tangent = (segment[1] - segment[0]).Normalize(); + m2::PointD const normal = isLeftHandTraffic ? m2::PointD(-tangent.y, tangent.x) : + m2::PointD(tangent.y, -tangent.x); + m2::PolylineD segmentPolyline(vector{segment[0] + normal * twoWayOffset, + segment[1] + normal * twoWayOffset}); + segments.emplace_back(sid, df::TrafficSegmentGeometry(move(segmentPolyline), roadClass)); + } + else + { + m2::PolylineD segmentPolyline(vector{segment[0], segment[1]}); + segments.emplace_back(sid, df::TrafficSegmentGeometry(move(segmentPolyline), roadClass)); + } } } } @@ -285,7 +314,9 @@ void RuleDrawer::operator()(FeatureType const & f) { vector points; points.reserve(f.GetPointsCount()); - f.ForEachPoint([&points](m2::PointD const & p) { points.emplace_back(p); }, FeatureType::BEST_GEOMETRY); + f.ResetGeometry(); + f.ForEachPoint([&points](m2::PointD const & p) { points.emplace_back(p); }, + FeatureType::BEST_GEOMETRY); m2::PolylineD const polyline(points); struct Checker @@ -295,17 +326,27 @@ void RuleDrawer::operator()(FeatureType const & f) df::RoadClass m_roadClass; }; static Checker const checkers[] = { - {{ftypes::HighwayClass::Trunk, ftypes::HighwayClass::Primary}, kRoadClass0ZoomLevel, df::RoadClass::Class0}, - {{ftypes::HighwayClass::Secondary, ftypes::HighwayClass::Tertiary}, kRoadClass1ZoomLevel, df::RoadClass::Class1}, - {{ftypes::HighwayClass::LivingStreet, ftypes::HighwayClass::Service}, kRoadClass2ZoomLevel, df::RoadClass::Class2} + {{ftypes::HighwayClass::Trunk, ftypes::HighwayClass::Primary}, + kRoadClass0ZoomLevel, df::RoadClass::Class0}, + {{ftypes::HighwayClass::Secondary, ftypes::HighwayClass::Tertiary}, + kRoadClass1ZoomLevel, df::RoadClass::Class1}, + {{ftypes::HighwayClass::LivingStreet, ftypes::HighwayClass::Service}, + kRoadClass2ZoomLevel, df::RoadClass::Class2} }; + bool const oneWay = ftypes::IsOneWayChecker::Instance()(f); auto const highwayClass = ftypes::GetHighwayClass(f); + double const pixelToGraphics = 1.0 / m_currentScaleGtoP; for (size_t i = 0; i < ARRAY_SIZE(checkers); ++i) { auto const & classes = checkers[i].m_highwayClasses; - if (find(classes.begin(), classes.end(), highwayClass) != classes.end() && zoomLevel >= checkers[i].m_zoomLevel) - ExtractTrafficGeometry(f, checkers[i].m_roadClass, polyline, m_trafficGeometry); + if (find(classes.begin(), classes.end(), highwayClass) != classes.end() && + zoomLevel >= checkers[i].m_zoomLevel) + { + ExtractTrafficGeometry(f, checkers[i].m_roadClass, polyline, oneWay, + zoomLevel, pixelToGraphics, m_trafficGeometry); + break; + } } } } diff --git a/drape_frontend/traffic_generator.cpp b/drape_frontend/traffic_generator.cpp index 65ac83a5a9..89850aa995 100644 --- a/drape_frontend/traffic_generator.cpp +++ b/drape_frontend/traffic_generator.cpp @@ -4,6 +4,7 @@ #include "drape_frontend/map_shape.hpp" #include "drape_frontend/shape_view_params.hpp" #include "drape_frontend/tile_utils.hpp" +#include "drape_frontend/traffic_renderer.hpp" #include "drape_frontend/visual_params.hpp" #include "drape/attribute_provider.hpp" @@ -211,10 +212,9 @@ void TrafficGenerator::FlushSegmentsGeometry(TileKey const & tileKey, TrafficSeg static vector const kRoadClasses = {RoadClass::Class0, RoadClass::Class1, RoadClass::Class2}; static float const kDepths[] = {2.0f, 1.0f, 0.0f}; - static int const kGenerateCapsZoomLevel[] = {13, 14, 16}; - static double const kVS = VisualParams::Instance().GetVisualScale(); - static unordered_map const kLineDrawerRoadClass1 = {{12, 2 * kVS}, {13, 3 * kVS}, {14, 4 * kVS}}; - static unordered_map const kLineDrawerRoadClass2 = {{15, 2 * kVS}, {16, 3 * kVS}}; + static int const kGenerateCapsZoomLevel[] = {14, 14, 16}; + static vector const kLineDrawerRoadClass1 = {12, 13, 14}; + static vector const kLineDrawerRoadClass2 = {15, 16}; for (auto geomIt = geom.begin(); geomIt != geom.end(); ++geomIt) { @@ -245,7 +245,7 @@ void TrafficGenerator::FlushSegmentsGeometry(TileKey const & tileKey, TrafficSeg glsl::vec2 const uv = glsl::ToVec2(colorRegion.GetTexRect().Center()); bool generatedAsLine = false; - unordered_map const * lineDrawer = nullptr; + vector const * lineDrawer = nullptr; if (g.m_roadClass == RoadClass::Class1) lineDrawer = &kLineDrawerRoadClass1; else if (g.m_roadClass == RoadClass::Class2) @@ -253,8 +253,9 @@ void TrafficGenerator::FlushSegmentsGeometry(TileKey const & tileKey, TrafficSeg if (lineDrawer != nullptr) { - auto lineDrawerIt = lineDrawer->find(tileKey.m_zoomLevel); - if (lineDrawerIt != lineDrawer->end() && lineDrawerIt->second <= dp::SupportManager::Instance().GetMaxLineWidth()) + auto lineDrawerIt = find(lineDrawer->begin(), lineDrawer->end(), tileKey.m_zoomLevel); + int const w = static_cast(TrafficRenderer::GetPixelWidth(g.m_roadClass, tileKey.m_zoomLevel)); + if (lineDrawerIt != lineDrawer->end() && w > 0 && w <= dp::SupportManager::Instance().GetMaxLineWidth()) { vector staticGeometry; vector dynamicGeometry; @@ -272,7 +273,7 @@ void TrafficGenerator::FlushSegmentsGeometry(TileKey const & tileKey, TrafficSeg provider.InitStream(1 /* stream index */, GetTrafficDynamicBindingInfo(), make_ref(dynamicGeometry.data())); dp::GLState curLineState = lineState; - curLineState.SetLineWidth(lineDrawerIt->second); + curLineState.SetLineWidth(w * df::VisualParams::Instance().GetVisualScale()); batcher->InsertLineStrip(curLineState, make_ref(&provider), move(handle)); generatedAsLine = true; } diff --git a/drape_frontend/traffic_renderer.cpp b/drape_frontend/traffic_renderer.cpp index 573a3f885a..fd4c94a201 100644 --- a/drape_frontend/traffic_renderer.cpp +++ b/drape_frontend/traffic_renderer.cpp @@ -21,40 +21,40 @@ namespace int constexpr kMinVisibleArrowZoomLevel = 16; int constexpr kRoadClass2MinVisibleArrowZoomLevel = 17; -int constexpr kOutlineMinZoomLevel = 13; +int constexpr kOutlineMinZoomLevel = 14; float const kTrafficArrowAspect = 24.0f / 8.0f; float const kLeftWidthInPixel[] = { - // 1 2 3 4 5 6 7 8 9 10 + // 1 2 3 4 5 6 7 8 9 10 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, - //11 12 13 14 15 16 17 18 19 20 - 0.75f, 0.75f, 0.75f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f + //11 12 13 14 15 16 17 18 19 20 + 0.5f, 0.5f, 0.5f, 0.5f, 2.0f, 2.5f, 3.0f, 4.0f, 4.0f, 7.0f }; float const kRightWidthInPixel[] = { - // 1 2 3 4 5 6 7 8 9 10 - 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, + // 1 2 3 4 5 6 7 8 9 10 + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 3.0f, 3.0f, //11 12 13 14 15 16 17 18 19 20 - 4.0f, 4.0f, 4.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 5.0f, 8.0f + 3.0f, 3.0f, 4.0f, 4.0f, 2.0f, 2.5f, 3.0f, 4.0f, 4.0f, 7.0f }; float const kRoadClass1WidthScalar[] = { - // 1 2 3 4 5 6 7 8 9 10 - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + // 1 2 3 4 5 6 7 8 9 10 + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.2, //11 12 13 14 15 16 17 18 19 20 - 0.0f, 0.2f, 0.3f, 0.6f, 0.8f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f + 0.2, 0.2f, 0.4f, 0.5f, 0.6f, 0.6f, 1.0f, 1.0f, 1.0f, 1.0f }; float const kRoadClass2WidthScalar[] = { // 1 2 3 4 5 6 7 8 9 10 - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - //11 12 13 14 15 16 17 18 19 20 - 0.0f, 0.0f, 0.0f, 0.0f, 0.3f, 0.5f, 0.7f, 0.8f, 0.9f, 1.0f + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.2f, + //11 12 13 14 15 16 17 18 19 20 + 0.2f, 0.2f, 0.2f, 0.2f, 0.5f, 0.5f, 0.5f, 0.8f, 0.9f, 1.0f }; float CalculateHalfWidth(ScreenBase const & screen, RoadClass const & roadClass, bool left) @@ -215,6 +215,7 @@ void TrafficRenderer::RenderTraffic(ScreenBase const & screen, int zoomLevel, fl } else if (handle->GetRoadClass() == RoadClass::Class1) { + outline = (zoomLevel <= kOutlineMinZoomLevel ? 1.0 : 0.0); visibleZoomLevel = kRoadClass1ZoomLevel; } else if (handle->GetRoadClass() == RoadClass::Class2) @@ -279,5 +280,20 @@ void TrafficRenderer::Clear(MwmSet::MwmId const & mwmId) m_renderData.erase(remove_if(m_renderData.begin(), m_renderData.end(), removePredicate), m_renderData.end()); } +// static +float TrafficRenderer::GetPixelWidth(RoadClass const & roadClass, int zoomLevel) +{ + ASSERT_GREATER(zoomLevel, 1, ()); + ASSERT_LESS_OR_EQUAL(zoomLevel, scales::GetUpperStyleScale(), ()); + float const * widthScalar = nullptr; + if (roadClass == RoadClass::Class1) + widthScalar = kRoadClass1WidthScalar; + else if (roadClass == RoadClass::Class2) + widthScalar = kRoadClass2WidthScalar; + + float const baseWidth = kLeftWidthInPixel[zoomLevel] + kRightWidthInPixel[zoomLevel]; + return (widthScalar != nullptr) ? (baseWidth * widthScalar[zoomLevel]) : baseWidth; +} + } // namespace df diff --git a/drape_frontend/traffic_renderer.hpp b/drape_frontend/traffic_renderer.hpp index 6532112766..916d1a69cf 100644 --- a/drape_frontend/traffic_renderer.hpp +++ b/drape_frontend/traffic_renderer.hpp @@ -40,6 +40,8 @@ public: buffer_vector const & tilesToDelete); void OnGeometryReady(int currentZoomLevel); + static float GetPixelWidth(RoadClass const & roadClass, int zoomLevel); + private: vector m_renderData; TrafficTexCoords m_texCoords; diff --git a/geometry/polyline2d.hpp b/geometry/polyline2d.hpp index abe2459ebe..9e96516bd5 100644 --- a/geometry/polyline2d.hpp +++ b/geometry/polyline2d.hpp @@ -115,13 +115,13 @@ public: return m_points.back(); } - Polyline ExtractSegment(size_t segmentIndex, bool reversed) const + vector> ExtractSegment(size_t segmentIndex, bool reversed) const { if (segmentIndex + 1 >= m_points.size()) - return Polyline(); + return vector>(); - return reversed ? Polyline(vector>{m_points[segmentIndex + 1], m_points[segmentIndex]}) : - Polyline(vector>{m_points[segmentIndex], m_points[segmentIndex + 1]}); + return reversed ? vector>{m_points[segmentIndex + 1], m_points[segmentIndex]} : + vector>{m_points[segmentIndex], m_points[segmentIndex + 1]}; } vector > const & GetPoints() const { return m_points; }