diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index a3a1b52707..f5f505fe5e 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -45,15 +45,15 @@ BackendRenderer::BackendRenderer(Params && params) ASSERT(m_updateCurrentCountryFn != nullptr, ()); - m_routeBuilder = make_unique_dp([this](drape_ptr && routeData) + m_routeBuilder = make_unique_dp([this](drape_ptr && subrouteData) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(std::move(routeData)), + make_unique_dp(std::move(subrouteData)), MessagePriority::Normal); - }, [this](drape_ptr && routeArrowsData) + }, [this](drape_ptr && subrouteArrowsData) { m_commutator->PostMessage(ThreadsCommutator::RenderThread, - make_unique_dp(std::move(routeArrowsData)), + make_unique_dp(std::move(subrouteArrowsData)), MessagePriority::Normal); }); @@ -304,9 +304,9 @@ void BackendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::CacheRouteArrows: + case Message::CacheSubrouteArrows: { - ref_ptr msg = message; + ref_ptr msg = message; m_routeBuilder->BuildArrows(msg->GetSubrouteId(), msg->GetBorders(), m_texMng, msg->GetRecacheId()); break; @@ -317,7 +317,7 @@ void BackendRenderer::AcceptMessage(ref_ptr message) ref_ptr msg = message; m_routeBuilder->ClearRouteCache(); // We have to resend the message to FR, because it guaranties that - // RemoveSubroute will be processed after FlushRouteMessage. + // RemoveSubroute will be processed after FlushSubrouteMessage. m_commutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp( msg->GetSegmentId(), msg->NeedDeactivateFollowing()), diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 4fd6b6d27c..2109b75a72 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -362,7 +362,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) } break; - case Message::ChangeMyPostitionMode: + case Message::ChangeMyPositionMode: { ref_ptr msg = message; switch (msg->GetChangeType()) @@ -428,20 +428,20 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::FlushRoute: + case Message::FlushSubroute: { - ref_ptr msg = message; - drape_ptr routeData = msg->AcceptRouteData(); + ref_ptr msg = message; + auto subrouteData = msg->AcceptSubrouteData(); - if (routeData->m_recacheId < 0) - routeData->m_recacheId = m_lastRecacheRouteId; + if (subrouteData->m_recacheId < 0) + subrouteData->m_recacheId = m_lastRecacheRouteId; - if (!CheckRouteRecaching(make_ref(routeData))) + if (!CheckRouteRecaching(make_ref(subrouteData))) break; - m_routeRenderer->ClearObsoleteRouteData(m_lastRecacheRouteId); + m_routeRenderer->ClearObsoleteData(m_lastRecacheRouteId); - m_routeRenderer->AddRouteData(std::move(routeData), make_ref(m_gpuProgramManager)); + m_routeRenderer->AddSubrouteData(std::move(subrouteData), make_ref(m_gpuProgramManager)); // Here we have to recache route arrows. m_routeRenderer->UpdateRoute(m_userEventStream.GetCurrentScreen(), @@ -457,14 +457,14 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } - case Message::FlushRouteArrows: + case Message::FlushSubrouteArrows: { - ref_ptr msg = message; - drape_ptr routeArrowsData = msg->AcceptRouteArrowsData(); + ref_ptr msg = message; + drape_ptr routeArrowsData = msg->AcceptSubrouteArrowsData(); if (CheckRouteRecaching(make_ref(routeArrowsData))) { - m_routeRenderer->AddRouteArrowsData(std::move(routeArrowsData), - make_ref(m_gpuProgramManager)); + m_routeRenderer->AddSubrouteArrowsData(std::move(routeArrowsData), + make_ref(m_gpuProgramManager)); } break; } @@ -483,7 +483,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) } else { - m_routeRenderer->RemoveRouteData(msg->GetSegmentId()); + m_routeRenderer->RemoveSubrouteData(msg->GetSegmentId()); } break; } @@ -493,8 +493,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) ref_ptr const msg = message; // After night style switching or drape engine reinitialization FrontendRenderer can - // receive FollowRoute message before FlushRoute message, so we need to postpone its processing. - if (m_routeRenderer->GetRouteData().empty()) + // receive FollowRoute message before FlushSubroute message, so we need to postpone its processing. + if (m_routeRenderer->GetSubroutes().empty()) { m_pendingFollowRoute = my::make_unique(msg->GetPreferredZoomLevel(), msg->GetPreferredZoomLevelIn3d(), @@ -832,10 +832,10 @@ void FrontendRenderer::UpdateGLResources() { ++m_lastRecacheRouteId; - for (auto const & routeData : m_routeRenderer->GetRouteData()) + for (auto const & subroute : m_routeRenderer->GetSubroutes()) { - auto msg = make_unique_dp(routeData->m_subrouteId, - routeData->m_subroute, + auto msg = make_unique_dp(subroute.m_subrouteId, + subroute.m_subroute, m_lastRecacheRouteId); m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, std::move(msg), MessagePriority::Normal); @@ -869,9 +869,9 @@ void FrontendRenderer::FollowRoute(int preferredZoomLevel, int preferredZoomLeve m_routeRenderer->SetFollowingEnabled(true); } -bool FrontendRenderer::CheckRouteRecaching(ref_ptr routeData) +bool FrontendRenderer::CheckRouteRecaching(ref_ptr subrouteData) { - return routeData->m_recacheId >= m_lastRecacheRouteId; + return subrouteData->m_recacheId >= m_lastRecacheRouteId; } void FrontendRenderer::InvalidateRect(m2::RectD const & gRect) @@ -2030,7 +2030,7 @@ void FrontendRenderer::EmitModelViewChanged(ScreenBase const & modelView) const void FrontendRenderer::OnCacheRouteArrows(int routeIndex, std::vector const & borders) { m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread, - make_unique_dp(routeIndex, borders, m_lastRecacheRouteId), + make_unique_dp(routeIndex, borders, m_lastRecacheRouteId), MessagePriority::Normal); } diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index fa4ecc8d52..5dc84a8759 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -222,7 +222,7 @@ private: void RemoveRenderGroupsLater(TRenderGroupRemovePredicate const & predicate); void FollowRoute(int preferredZoomLevel, int preferredZoomLevelIn3d, bool enableAutoZoom); - bool CheckRouteRecaching(ref_ptr routeData); + bool CheckRouteRecaching(ref_ptr subrouteData); void InvalidateRect(m2::RectD const & gRect); bool CheckTileGenerations(TileKey const & tileKey); diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 2577d605f9..c5a8ca5f32 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -31,15 +31,15 @@ public: GuiLayerLayout, MapShapesRecache, MapShapes, - ChangeMyPostitionMode, + ChangeMyPositionMode, CompassInfo, GpsInfo, SelectObject, AddSubroute, RemoveSubroute, - CacheRouteArrows, - FlushRoute, - FlushRouteArrows, + CacheSubrouteArrows, + FlushSubroute, + FlushSubrouteArrows, FollowRoute, DeactivateRouteFollowing, SetSubrouteVisibility, diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index b9abd2b688..29259d4303 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -465,7 +465,7 @@ public: {} EChangeType GetChangeType() const { return m_changeType; } - Type GetType() const override { return Message::ChangeMyPostitionMode; } + Type GetType() const override { return Message::ChangeMyPositionMode; } private: EChangeType const m_changeType; @@ -570,17 +570,18 @@ private: int const m_recacheId; }; -class CacheRouteArrowsMessage : public Message +class CacheSubrouteArrowsMessage : public Message { public: - CacheRouteArrowsMessage(dp::DrapeID subrouteId, std::vector const & borders, - int recacheId) + CacheSubrouteArrowsMessage(dp::DrapeID subrouteId, + std::vector const & borders, + int recacheId) : m_subrouteId(subrouteId) , m_borders(borders) , m_recacheId(recacheId) {} - Type GetType() const override { return Message::CacheRouteArrows; } + Type GetType() const override { return Message::CacheSubrouteArrows; } dp::DrapeID GetSubrouteId() const { return m_subrouteId; } std::vector const & GetBorders() const { return m_borders; } int GetRecacheId() const { return m_recacheId; } @@ -609,36 +610,36 @@ private: bool m_deactivateFollowing; }; -class FlushRouteMessage : public Message +class FlushSubrouteMessage : public Message { public: - FlushRouteMessage(drape_ptr && routeData) - : m_routeData(std::move(routeData)) + explicit FlushSubrouteMessage(drape_ptr && subrouteData) + : m_subrouteData(std::move(subrouteData)) {} - Type GetType() const override { return Message::FlushRoute; } + Type GetType() const override { return Message::FlushSubroute; } bool IsGLContextDependent() const override { return true; } - drape_ptr && AcceptRouteData() { return std::move(m_routeData); } + drape_ptr && AcceptSubrouteData() { return std::move(m_subrouteData); } private: - drape_ptr m_routeData; + drape_ptr m_subrouteData; }; -class FlushRouteArrowsMessage : public Message +class FlushSubrouteArrowsMessage : public Message { public: - FlushRouteArrowsMessage(drape_ptr && routeArrowsData) - : m_routeArrowsData(std::move(routeArrowsData)) + explicit FlushSubrouteArrowsMessage(drape_ptr && subrouteArrowsData) + : m_subrouteArrowsData(std::move(subrouteArrowsData)) {} - Type GetType() const override { return Message::FlushRouteArrows; } + Type GetType() const override { return Message::FlushSubrouteArrows; } bool IsGLContextDependent() const override { return true; } - drape_ptr && AcceptRouteArrowsData() { return std::move(m_routeArrowsData); } + drape_ptr && AcceptSubrouteArrowsData() { return std::move(m_subrouteArrowsData); } private: - drape_ptr m_routeArrowsData; + drape_ptr m_subrouteArrowsData; }; class AddRoutePreviewSegmentMessage : public Message diff --git a/drape_frontend/route_builder.cpp b/drape_frontend/route_builder.cpp index 8af31c2b50..a8d8da3c29 100644 --- a/drape_frontend/route_builder.cpp +++ b/drape_frontend/route_builder.cpp @@ -2,6 +2,55 @@ #include "drape_frontend/route_shape.hpp" +namespace +{ +std::vector> SplitSubroute(dp::DrapeID subrouteId, + df::SubrouteConstPtr subroute, + int recacheId) +{ + ASSERT(subroute != nullptr, ()); + + std::vector> result; + if (subroute->m_styleType == df::SubrouteStyleType::Single) + { + ASSERT(!subroute->m_style.empty(), ()); + auto subrouteData = make_unique_dp(); + subrouteData->m_subrouteId = subrouteId; + subrouteData->m_subroute = subroute; + subrouteData->m_pivot = subrouteData->m_subroute->m_polyline.GetLimitRect().Center(); + subrouteData->m_recacheId = recacheId; + subrouteData->m_styleIndex = 0; + subrouteData->m_startPointIndex = 0; + subrouteData->m_endPointIndex = subrouteData->m_subroute->m_polyline.GetSize() - 1; + result.push_back(std::move(subrouteData)); + return result; + } + + ASSERT_EQUAL(subroute->m_style.size() + 1, subroute->m_polyline.GetSize(), ()); + + size_t startIndex = 0; + result.reserve(10); + for (size_t i = 1; i <= subroute->m_style.size(); ++i) + { + if (i == subroute->m_style.size() || subroute->m_style[i] != subroute->m_style[startIndex]) + { + auto subrouteData = make_unique_dp(); + subrouteData->m_subrouteId = subrouteId; + subrouteData->m_subroute = subroute; + subrouteData->m_startPointIndex = startIndex; + subrouteData->m_endPointIndex = i; + subrouteData->m_styleIndex = startIndex; + subrouteData->m_pivot = subrouteData->m_subroute->m_polyline.GetLimitRect().Center(); + subrouteData->m_recacheId = recacheId; + result.push_back(std::move(subrouteData)); + + startIndex = i; + } + } + return result; +} +} // namespace + namespace df { RouteBuilder::RouteBuilder(TFlushRouteFn const & flushRouteFn, @@ -13,22 +62,24 @@ RouteBuilder::RouteBuilder(TFlushRouteFn const & flushRouteFn, void RouteBuilder::Build(dp::DrapeID subrouteId, SubrouteConstPtr subroute, ref_ptr textures, int recacheId) { - drape_ptr routeData = make_unique_dp(); - routeData->m_subrouteId = subrouteId; - routeData->m_subroute = subroute; - routeData->m_pivot = routeData->m_subroute->m_polyline.GetLimitRect().Center(); - routeData->m_recacheId = recacheId; - RouteShape::CacheRoute(textures, *routeData.get()); RouteCacheData cacheData; - cacheData.m_polyline = routeData->m_subroute->m_polyline; - cacheData.m_baseDepthIndex = routeData->m_subroute->m_baseDepthIndex; - m_routeCache.insert(std::make_pair(subrouteId, std::move(cacheData))); + cacheData.m_polyline = subroute->m_polyline; + cacheData.m_baseDepthIndex = subroute->m_baseDepthIndex; + m_routeCache[subrouteId] = std::move(cacheData); + + auto subrouteData = SplitSubroute(subrouteId, subroute, recacheId); + for (auto & data : subrouteData) + RouteShape::CacheRoute(textures, *data.get()); // Flush route geometry. GLFunctions::glFlush(); if (m_flushRouteFn != nullptr) - m_flushRouteFn(std::move(routeData)); + { + for (auto & data : subrouteData) + m_flushRouteFn(std::move(data)); + subrouteData.clear(); + } } void RouteBuilder::ClearRouteCache() @@ -43,7 +94,7 @@ void RouteBuilder::BuildArrows(dp::DrapeID subrouteId, std::vector if (it == m_routeCache.end()) return; - drape_ptr routeArrowsData = make_unique_dp(); + drape_ptr routeArrowsData = make_unique_dp(); routeArrowsData->m_subrouteId = subrouteId; routeArrowsData->m_pivot = it->second.m_polyline.GetLimitRect().Center(); routeArrowsData->m_recacheId = recacheId; diff --git a/drape_frontend/route_builder.hpp b/drape_frontend/route_builder.hpp index 8e483e3973..e2e2576a30 100644 --- a/drape_frontend/route_builder.hpp +++ b/drape_frontend/route_builder.hpp @@ -19,8 +19,8 @@ namespace df class RouteBuilder { public: - using TFlushRouteFn = function &&)>; - using TFlushRouteArrowsFn = function &&)>; + using TFlushRouteFn = function &&)>; + using TFlushRouteArrowsFn = function &&)>; RouteBuilder(TFlushRouteFn const & flushRouteFn, TFlushRouteArrowsFn const & flushRouteArrowsFn); diff --git a/drape_frontend/route_renderer.cpp b/drape_frontend/route_renderer.cpp index f0cd20fde7..8ae2116de7 100644 --- a/drape_frontend/route_renderer.cpp +++ b/drape_frontend/route_renderer.cpp @@ -158,10 +158,11 @@ bool AreEqualArrowBorders(std::vector const & borders1, } std::vector CalculateArrowBorders(ScreenBase const & screen, float currentHalfWidth, - drape_ptr const & routeData, + RouteRenderer::SubrouteInfo const & subrouteInfo, double distanceFromBegin) { - if (routeData->m_subroute->m_turns.empty()) + auto const & turns = subrouteInfo.m_subroute->m_turns; + if (turns.empty()) return {}; // Calculate arrow mercator length. @@ -179,17 +180,16 @@ std::vector CalculateArrowBorders(ScreenBase const & screen, float m2::RectD screenRect = screen.ClipRect(); screenRect.Scale(kExtendCoef); - auto const & subroute = routeData->m_subroute; - // Calculate arrow borders. std::vector newArrowBorders; - newArrowBorders.reserve(subroute->m_turns.size()); - for (size_t i = 0; i < subroute->m_turns.size(); i++) + newArrowBorders.reserve(turns.size()); + auto const & polyline = subrouteInfo.m_subroute->m_polyline; + for (size_t i = 0; i < turns.size(); i++) { ArrowBorders arrowBorders; arrowBorders.m_groupIndex = static_cast(i); - arrowBorders.m_startDistance = std::max(0.0, subroute->m_turns[i] - glbHalfLen * 0.8); - arrowBorders.m_endDistance = std::min(routeData->m_length, subroute->m_turns[i] + glbHalfLen * 1.2); + arrowBorders.m_startDistance = std::max(0.0, turns[i] - glbHalfLen * 0.8); + arrowBorders.m_endDistance = std::min(subrouteInfo.m_length, turns[i] + glbHalfLen * 1.2); if ((arrowBorders.m_endDistance - arrowBorders.m_startDistance) < glbMinArrowSize || arrowBorders.m_startDistance < distanceFromBegin) @@ -197,14 +197,14 @@ std::vector CalculateArrowBorders(ScreenBase const & screen, float continue; } - m2::PointD pt = subroute->m_polyline.GetPointByDistance(arrowBorders.m_startDistance); + m2::PointD pt = polyline.GetPointByDistance(arrowBorders.m_startDistance); if (screenRect.IsPointInside(pt)) { newArrowBorders.push_back(arrowBorders); continue; } - pt = subroute->m_polyline.GetPointByDistance(arrowBorders.m_endDistance); + pt = polyline.GetPointByDistance(arrowBorders.m_endDistance); if (screenRect.IsPointInside(pt)) { newArrowBorders.push_back(arrowBorders); @@ -231,12 +231,14 @@ void BuildBuckets(RouteRenderProperty const & renderProperty, ref_ptrGetBuffer()->Build(mng->GetProgram(renderProperty.m_state.GetProgramIndex())); } -dp::Color GetOutlineColor(SubrouteConstPtr const & subroute) +RouteRenderer::Subroutes::iterator FindSubroute(RouteRenderer::Subroutes & subroutes, + dp::DrapeID subrouteId) { - if (subroute->m_routeType == RouteType::Car || subroute->m_routeType == RouteType::Taxi) - return df::GetColorConstant(kRouteOutlineColor); - - return df::GetColorConstant(subroute->m_color); + return std::find_if(subroutes.begin(), subroutes.end(), + [&subrouteId](RouteRenderer::SubrouteInfo const & info) + { + return info.m_subrouteId == subrouteId; + }); } } // namespace @@ -252,40 +254,36 @@ RouteRenderer::RouteRenderer(PreviewPointsRequestCallback && previewPointsReques void RouteRenderer::UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallback const & callback) { ASSERT(callback != nullptr, ()); - for (auto const & routeData : m_routeData) + for (auto & subrouteInfo : m_subroutes) { - auto & additional = m_routeAdditional[routeData->m_subrouteId]; - // Interpolate values by zoom level. double zoom = 0.0; float halfWidth = 0.0; - InterpolateByZoom(routeData->m_subroute, screen, halfWidth, zoom); - additional.m_routeType = routeData->m_subroute->m_routeType; - additional.m_currentHalfWidth = halfWidth; - additional.m_baseDistance = routeData->m_subroute->m_baseDistance; + InterpolateByZoom(subrouteInfo.m_subroute, screen, halfWidth, zoom); + subrouteInfo.m_currentHalfWidth = halfWidth; if (zoom < kArrowAppearingZoomLevel) { - additional.m_arrowsData.reset(); - additional.m_arrowBorders.clear(); + subrouteInfo.m_arrowsData.reset(); + subrouteInfo.m_arrowBorders.clear(); continue; } // Calculate arrow borders. double dist = kInvalidDistance; if (m_followingEnabled) - dist = m_distanceFromBegin - routeData->m_subroute->m_baseDistance; - auto newArrowBorders = CalculateArrowBorders(screen, halfWidth, routeData, dist); + dist = m_distanceFromBegin - subrouteInfo.m_subroute->m_baseDistance; + auto newArrowBorders = CalculateArrowBorders(screen, halfWidth, subrouteInfo, dist); if (newArrowBorders.empty()) { // Clear arrows. - additional.m_arrowsData.reset(); - additional.m_arrowBorders.clear(); + subrouteInfo.m_arrowsData.reset(); + subrouteInfo.m_arrowBorders.clear(); } - else if (!AreEqualArrowBorders(newArrowBorders, additional.m_arrowBorders)) + else if (!AreEqualArrowBorders(newArrowBorders, subrouteInfo.m_arrowBorders)) { - additional.m_arrowBorders = std::move(newArrowBorders); - callback(routeData->m_subrouteId, additional.m_arrowBorders); + subrouteInfo.m_arrowBorders = std::move(newArrowBorders); + callback(subrouteInfo.m_subrouteId, subrouteInfo.m_arrowBorders); } } } @@ -385,92 +383,96 @@ dp::Color RouteRenderer::GetMaskColor(RouteType routeType, double baseDistance, return {0, 0, 0, 0}; } -void RouteRenderer::RenderRouteData(drape_ptr const & routeData, - ScreenBase const & screen, bool trafficShown, - ref_ptr mng, - dp::UniformValuesStorage const & commonUniforms) +void RouteRenderer::RenderSubroute(SubrouteInfo const & subrouteInfo, size_t subrouteDataIndex, + ScreenBase const & screen, bool trafficShown, + ref_ptr mng, + dp::UniformValuesStorage const & commonUniforms) { - if (routeData->m_renderProperty.m_buckets.empty()) + ASSERT_LESS(subrouteDataIndex, subrouteInfo.m_subrouteData.size(), ()); + if (subrouteInfo.m_subrouteData[subrouteDataIndex]->m_renderProperty.m_buckets.empty()) return; // Skip rendering of hidden subroutes. - if (m_hiddenSubroutes.find(routeData->m_subrouteId) != m_hiddenSubroutes.end()) + if (m_hiddenSubroutes.find(subrouteInfo.m_subrouteId) != m_hiddenSubroutes.end()) return; - float const currentHalfWidth = m_routeAdditional[routeData->m_subrouteId].m_currentHalfWidth; - auto const screenHalfWidth = static_cast(currentHalfWidth * screen.GetScale()); + auto const screenHalfWidth = static_cast(subrouteInfo.m_currentHalfWidth * screen.GetScale()); auto dist = static_cast(kInvalidDistance); if (m_followingEnabled) - dist = static_cast(m_distanceFromBegin - routeData->m_subroute->m_baseDistance); + dist = static_cast(m_distanceFromBegin - subrouteInfo.m_subroute->m_baseDistance); - dp::GLState const & state = routeData->m_renderProperty.m_state; - auto const & subroute = routeData->m_subroute; + auto const & subrouteData = subrouteInfo.m_subrouteData[subrouteDataIndex]; + dp::GLState const & state = subrouteData->m_renderProperty.m_state; + size_t const styleIndex = subrouteData->m_styleIndex; + ASSERT_LESS(styleIndex, subrouteInfo.m_subroute->m_style.size(), ()); + auto const & style = subrouteInfo.m_subroute->m_style[styleIndex]; // Set up uniforms. dp::UniformValuesStorage uniforms = commonUniforms; - math::Matrix mv = screen.GetModelView(routeData->m_pivot, kShapeCoordScalar); + math::Matrix mv = screen.GetModelView(subrouteData->m_pivot, kShapeCoordScalar); uniforms.SetMatrix4x4Value("modelView", mv.m_data); - glsl::vec4 const color = glsl::ToVec4(df::GetColorConstant(subroute->m_color)); + glsl::vec4 const color = glsl::ToVec4(df::GetColorConstant(style.m_color)); uniforms.SetFloatValue("u_color", color.r, color.g, color.b, color.a); - uniforms.SetFloatValue("u_routeParams", currentHalfWidth, screenHalfWidth, dist, + uniforms.SetFloatValue("u_routeParams", subrouteInfo.m_currentHalfWidth, screenHalfWidth, dist, trafficShown ? 1.0f : 0.0f); - glsl::vec4 const maskColor = glsl::ToVec4(GetMaskColor(routeData->m_subroute->m_routeType, - routeData->m_subroute->m_baseDistance, + glsl::vec4 const maskColor = glsl::ToVec4(GetMaskColor(subrouteData->m_subroute->m_routeType, + subrouteData->m_subroute->m_baseDistance, false /* arrows */)); uniforms.SetFloatValue("u_maskColor", maskColor.r, maskColor.g, maskColor.b, maskColor.a); - if (subroute->m_pattern.m_isDashed) + if (style.m_pattern.m_isDashed) { uniforms.SetFloatValue("u_pattern", - static_cast(screenHalfWidth * subroute->m_pattern.m_dashLength), - static_cast(screenHalfWidth * subroute->m_pattern.m_gapLength)); + static_cast(screenHalfWidth * style.m_pattern.m_dashLength), + static_cast(screenHalfWidth * style.m_pattern.m_gapLength)); } else { - glsl::vec4 const outlineColor = glsl::ToVec4(GetOutlineColor(subroute)); + glsl::vec4 const outlineColor = glsl::ToVec4(df::GetColorConstant(style.m_outlineColor)); uniforms.SetFloatValue("u_outlineColor", outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a); } // Set up shaders and apply uniforms. - ref_ptr prg = mng->GetProgram(subroute->m_pattern.m_isDashed ? + ref_ptr prg = mng->GetProgram(style.m_pattern.m_isDashed ? gpu::ROUTE_DASH_PROGRAM : gpu::ROUTE_PROGRAM); prg->Bind(); dp::ApplyState(state, prg); dp::ApplyUniforms(uniforms, prg); // Render buckets. - for (auto const & bucket : routeData->m_renderProperty.m_buckets) + for (auto const & bucket : subrouteData->m_renderProperty.m_buckets) bucket->Render(state.GetDrawAsLine()); } -void RouteRenderer::RenderRouteArrowData(dp::DrapeID subrouteId, RouteAdditional const & routeAdditional, - ScreenBase const & screen, ref_ptr mng, +void RouteRenderer::RenderSubrouteArrows(SubrouteInfo const & subrouteInfo, + ScreenBase const & screen, + ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { - if (routeAdditional.m_arrowsData == nullptr || - routeAdditional.m_arrowsData->m_renderProperty.m_buckets.empty() || - m_hiddenSubroutes.find(subrouteId) != m_hiddenSubroutes.end()) + if (subrouteInfo.m_arrowsData == nullptr || + subrouteInfo.m_arrowsData->m_renderProperty.m_buckets.empty() || + m_hiddenSubroutes.find(subrouteInfo.m_subrouteId) != m_hiddenSubroutes.end()) { return; } - float const currentHalfWidth = m_routeAdditional[subrouteId].m_currentHalfWidth; - dp::GLState const & state = routeAdditional.m_arrowsData->m_renderProperty.m_state; + dp::GLState const & state = subrouteInfo.m_arrowsData->m_renderProperty.m_state; // Set up shaders and apply common uniforms. dp::UniformValuesStorage uniforms = commonUniforms; - math::Matrix mv = screen.GetModelView(routeAdditional.m_arrowsData->m_pivot, + math::Matrix mv = screen.GetModelView(subrouteInfo.m_arrowsData->m_pivot, kShapeCoordScalar); uniforms.SetMatrix4x4Value("modelView", mv.m_data); - uniforms.SetFloatValue("u_arrowHalfWidth", static_cast(currentHalfWidth * kArrowHeightFactor)); + auto const arrowHalfWidth = static_cast(subrouteInfo.m_currentHalfWidth * kArrowHeightFactor); + uniforms.SetFloatValue("u_arrowHalfWidth", arrowHalfWidth); uniforms.SetFloatValue("u_opacity", 1.0f); - glsl::vec4 const maskColor = glsl::ToVec4(GetMaskColor(routeAdditional.m_routeType, - routeAdditional.m_baseDistance, + glsl::vec4 const maskColor = glsl::ToVec4(GetMaskColor(subrouteInfo.m_subroute->m_routeType, + subrouteInfo.m_subroute->m_baseDistance, true /* arrows */)); uniforms.SetFloatValue("u_maskColor", maskColor.r, maskColor.g, maskColor.b, maskColor.a); @@ -478,7 +480,7 @@ void RouteRenderer::RenderRouteArrowData(dp::DrapeID subrouteId, RouteAdditional prg->Bind(); dp::ApplyState(state, prg); dp::ApplyUniforms(uniforms, prg); - for (auto const & bucket : routeAdditional.m_arrowsData->m_renderProperty.m_buckets) + for (auto const & bucket : subrouteInfo.m_arrowsData->m_renderProperty.m_buckets) bucket->Render(state.GetDrawAsLine()); } @@ -511,60 +513,92 @@ void RouteRenderer::RenderRoute(ScreenBase const & screen, bool trafficShown, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { - if (!m_routeData.empty()) + if (!m_subroutes.empty()) { - // Render route. - for (auto const & routeData : m_routeData) - RenderRouteData(routeData, screen, trafficShown, mng, commonUniforms); + for (auto const & subroute : m_subroutes) + { + // Render subroutes. + for (size_t i = 0; i < subroute.m_subrouteData.size(); ++i) + RenderSubroute(subroute, i, screen, trafficShown, mng, commonUniforms); - // Render arrows. - for (auto const & p : m_routeAdditional) - RenderRouteArrowData(p.first, p.second, screen, mng, commonUniforms); + // Render arrows. + RenderSubrouteArrows(subroute, screen, mng, commonUniforms); + } } // Render preview. RenderPreviewData(screen, mng, commonUniforms); } -void RouteRenderer::AddRouteData(drape_ptr && routeData, - ref_ptr mng) +void RouteRenderer::AddSubrouteData(drape_ptr && subrouteData, + ref_ptr mng) { - // Remove old route data with the same id. - RemoveRouteData(routeData->m_subrouteId); - - // Add new route data. - m_routeData.push_back(std::move(routeData)); - BuildBuckets(m_routeData.back()->m_renderProperty, mng); - std::sort(m_routeData.begin(), m_routeData.end(), - [](drape_ptr const & d1, drape_ptr const & d2) + auto const it = FindSubroute(m_subroutes, subrouteData->m_subrouteId); + if (it != m_subroutes.end()) { - return d1->m_subroute->m_baseDistance > d2->m_subroute->m_baseDistance; - }); -} + if (!it->m_subrouteData.empty()) + { + int const recacheId = it->m_subrouteData.front()->m_recacheId; + if (recacheId < subrouteData->m_recacheId) + { + // Remove obsolete subroute data. + it->m_subrouteData.clear(); + it->m_arrowsData.reset(); + it->m_arrowBorders.clear(); -std::vector> const & RouteRenderer::GetRouteData() const -{ - return m_routeData; -} + it->m_subroute = subrouteData->m_subroute; + it->m_subrouteId = subrouteData->m_subrouteId; + it->m_length = subrouteData->m_subroute->m_polyline.GetLength(); + } + else if (recacheId > subrouteData->m_recacheId) + { + return; + } + } -void RouteRenderer::RemoveRouteData(dp::DrapeID subrouteId) -{ - auto const functor = [&subrouteId](drape_ptr const & data) + it->m_subrouteData.push_back(std::move(subrouteData)); + BuildBuckets(it->m_subrouteData.back()->m_renderProperty, mng); + } + else { - return data->m_subrouteId == subrouteId; - }; - m_routeData.erase(std::remove_if(m_routeData.begin(), m_routeData.end(), functor), - m_routeData.end()); - m_routeAdditional[subrouteId].m_arrowsData.reset(); - m_routeAdditional[subrouteId].m_arrowBorders.clear(); + // Add new subroute. + SubrouteInfo info; + info.m_subroute = subrouteData->m_subroute; + info.m_subrouteId = subrouteData->m_subrouteId; + info.m_length = subrouteData->m_subroute->m_polyline.GetLength(); + info.m_subrouteData.push_back(std::move(subrouteData)); + BuildBuckets(info.m_subrouteData.back()->m_renderProperty, mng); + m_subroutes.push_back(std::move(info)); + + std::sort(m_subroutes.begin(), m_subroutes.end(), + [](SubrouteInfo const & info1, SubrouteInfo const & info2) + { + return info1.m_subroute->m_baseDistance > info2.m_subroute->m_baseDistance; + }); + } } -void RouteRenderer::AddRouteArrowsData(drape_ptr && routeArrowsData, - ref_ptr mng) +void RouteRenderer::AddSubrouteArrowsData(drape_ptr && routeArrowsData, + ref_ptr mng) { - auto & additional = m_routeAdditional[routeArrowsData->m_subrouteId]; - additional.m_arrowsData = std::move(routeArrowsData); - BuildBuckets(additional.m_arrowsData->m_renderProperty, mng); + auto const it = FindSubroute(m_subroutes, routeArrowsData->m_subrouteId); + if (it != m_subroutes.end()) + { + it->m_arrowsData = std::move(routeArrowsData); + BuildBuckets(it->m_arrowsData->m_renderProperty, mng); + } +} + +RouteRenderer::Subroutes const & RouteRenderer::GetSubroutes() const +{ + return m_subroutes; +} + +void RouteRenderer::RemoveSubrouteData(dp::DrapeID subrouteId) +{ + auto const it = FindSubroute(m_subroutes, subrouteId); + if (it != m_subroutes.end()) + m_subroutes.erase(it); } void RouteRenderer::AddPreviewRenderData(drape_ptr && renderData, @@ -585,50 +619,32 @@ void RouteRenderer::AddPreviewRenderData(drape_ptr && ren m_previewHandlesCache.emplace_back(std::make_pair(handle, 0)); } -void RouteRenderer::ClearRouteData() +void RouteRenderer::ClearObsoleteData(int currentRecacheId) { - m_routeData.clear(); - m_routeAdditional.clear(); - m_hiddenSubroutes.clear(); -} - -void RouteRenderer::ClearObsoleteRouteData(int currentRecacheId) -{ - std::vector deletedSubroutes; - deletedSubroutes.reserve(m_routeData.size()); - auto const functor = [&deletedSubroutes, ¤tRecacheId](drape_ptr const & data) + auto const functor = [¤tRecacheId](SubrouteInfo const & subrouteInfo) { - if (data->m_recacheId < currentRecacheId) - { - deletedSubroutes.push_back(data->m_subrouteId); - return true; - } - return false; + return !subrouteInfo.m_subrouteData.empty() && + subrouteInfo.m_subrouteData.front()->m_recacheId < currentRecacheId; }; - m_routeData.erase(std::remove_if(m_routeData.begin(), m_routeData.end(), functor), - m_routeData.end()); - - for (auto const & subrouteId : deletedSubroutes) - { - m_routeAdditional[subrouteId].m_arrowsData.reset(); - m_routeAdditional[subrouteId].m_arrowBorders.clear(); - } + m_subroutes.erase(std::remove_if(m_subroutes.begin(), m_subroutes.end(), functor), + m_subroutes.end()); } void RouteRenderer::Clear() { - ClearRouteData(); + m_subroutes.clear(); m_distanceFromBegin = kInvalidDistance; } void RouteRenderer::ClearGLDependentResources() { - // Here we clear only GL-dependent part of route data. - for (auto & routeData : m_routeData) - routeData->m_renderProperty = RouteRenderProperty(); - - // All additional data (like arrows) will be regenerated, so clear them all. - m_routeAdditional.clear(); + // Here we clear only GL-dependent part of subroute data. + for (auto & subroute : m_subroutes) + { + subroute.m_subrouteData.clear(); + subroute.m_arrowsData.reset(); + subroute.m_arrowBorders.clear(); + } m_previewRenderData.clear(); m_previewHandlesCache.clear(); @@ -647,8 +663,6 @@ void RouteRenderer::SetFollowingEnabled(bool enabled) void RouteRenderer::AddPreviewSegment(dp::DrapeID id, PreviewInfo && info) { - if (m_previewSegments.empty()) - m_showPreviewTimestamp = std::chrono::steady_clock::now(); m_previewSegments.insert(std::make_pair(id, std::move(info))); } diff --git a/drape_frontend/route_renderer.hpp b/drape_frontend/route_renderer.hpp index 6ad568faba..5a1adf6638 100644 --- a/drape_frontend/route_renderer.hpp +++ b/drape_frontend/route_renderer.hpp @@ -35,20 +35,33 @@ public: m2::PointD m_finishPoint; }; - RouteRenderer(PreviewPointsRequestCallback && previewPointsRequest); + struct SubrouteInfo + { + dp::DrapeID m_subrouteId = 0; + SubrouteConstPtr m_subroute; + double m_length = 0.0; + std::vector> m_subrouteData; + + drape_ptr m_arrowsData; + std::vector m_arrowBorders; + float m_currentHalfWidth = 0.0f; + }; + using Subroutes = std::vector; + + explicit RouteRenderer(PreviewPointsRequestCallback && previewPointsRequest); void UpdateRoute(ScreenBase const & screen, CacheRouteArrowsCallback const & callback); void RenderRoute(ScreenBase const & screen, bool trafficShown, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms); - void AddRouteData(drape_ptr && routeData, ref_ptr mng); - std::vector> const & GetRouteData() const; + void AddSubrouteData(drape_ptr && subrouteData, ref_ptr mng); + Subroutes const & GetSubroutes() const; - void RemoveRouteData(dp::DrapeID subrouteId); + void RemoveSubrouteData(dp::DrapeID subrouteId); - void AddRouteArrowsData(drape_ptr && routeArrowsData, - ref_ptr mng); + void AddSubrouteArrowsData(drape_ptr && subrouteArrowsData, + ref_ptr mng); void AddPreviewRenderData(drape_ptr && renderData, ref_ptr mng); @@ -56,8 +69,7 @@ public: void UpdatePreview(ScreenBase const & screen); void Clear(); - void ClearRouteData(); - void ClearObsoleteRouteData(int currentRecacheId); + void ClearObsoleteData(int currentRecacheId); void ClearGLDependentResources(); void UpdateDistanceFromBegin(double distanceFromBegin); @@ -70,20 +82,11 @@ public: void SetSubrouteVisibility(dp::DrapeID id, bool isVisible); private: - struct RouteAdditional - { - RouteType m_routeType = RouteType::Car; - drape_ptr m_arrowsData; - std::vector m_arrowBorders; - float m_currentHalfWidth = 0.0f; - double m_baseDistance = 0.0; - }; - - void RenderRouteData(drape_ptr const & routeData, ScreenBase const & screen, - bool trafficShown, ref_ptr mng, - dp::UniformValuesStorage const & commonUniforms); - void RenderRouteArrowData(dp::DrapeID subrouteId, RouteAdditional const & routeAdditional, - ScreenBase const & screen, ref_ptr mng, + void RenderSubroute(SubrouteInfo const & subrouteInfo, size_t subrouteDataIndex, + ScreenBase const & screen, bool trafficShown, ref_ptr mng, + dp::UniformValuesStorage const & commonUniforms); + void RenderSubrouteArrows(SubrouteInfo const & subrouteInfo, ScreenBase const & screen, + ref_ptr mng, dp::UniformValuesStorage const & commonUniforms); void RenderPreviewData(ScreenBase const & screen, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms); @@ -92,9 +95,8 @@ private: dp::Color GetMaskColor(RouteType routeType, double baseDistance, bool arrows) const; double m_distanceFromBegin; - std::vector> m_routeData; - std::unordered_map m_routeAdditional; bool m_followingEnabled; + Subroutes m_subroutes; std::unordered_set m_hiddenSubroutes; PreviewPointsRequestCallback m_previewPointsRequest; @@ -103,6 +105,5 @@ private: bool m_waitForPreviewRenderData; std::unordered_map m_previewSegments; m2::PointD m_previewPivot = m2::PointD::Zero(); - std::chrono::steady_clock::time_point m_showPreviewTimestamp; }; } // namespace df diff --git a/drape_frontend/route_shape.cpp b/drape_frontend/route_shape.cpp index dae56fd92a..4d0c6444e7 100644 --- a/drape_frontend/route_shape.cpp +++ b/drape_frontend/route_shape.cpp @@ -135,8 +135,7 @@ void GenerateArrowsTriangles(glsl::vec4 const & pivot, std::vector c void RouteShape::PrepareGeometry(std::vector const & path, m2::PointD const & pivot, std::vector const & segmentsColors, float baseDepth, - TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry, - double & outputLength) + TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry) { ASSERT(path.size() > 1, ()); @@ -152,7 +151,6 @@ void RouteShape::PrepareGeometry(std::vector const & path, m2::Point float length = 0.0f; for (size_t i = 0; i < segments.size() ; ++i) length += glsl::length(segments[i].m_points[EndPoint] - segments[i].m_points[StartPoint]); - outputLength = length; float depth = baseDepth; float const depthStep = kRouteDepth / (1 + segments.size()); @@ -370,7 +368,7 @@ void RouteShape::PrepareArrowGeometry(std::vector const & path, m2:: void RouteShape::CacheRouteArrows(ref_ptr mng, m2::PolylineD const & polyline, std::vector const & borders, double baseDepthIndex, - RouteArrowsData & routeArrowsData) + SubrouteArrowsData & routeArrowsData) { TArrowGeometryBuffer geometry; TArrowGeometryBuffer joinsGeometry; @@ -396,35 +394,44 @@ void RouteShape::CacheRouteArrows(ref_ptr mng, m2::PolylineD AV::GetBindingInfo(), routeArrowsData.m_renderProperty); } -void RouteShape::CacheRoute(ref_ptr textures, RouteData & routeData) +void RouteShape::CacheRoute(ref_ptr textures, SubrouteData & subrouteData) { + ASSERT_LESS(subrouteData.m_startPointIndex, subrouteData.m_endPointIndex, ()); + + auto const points = subrouteData.m_subroute->m_polyline.ExtractSegment(subrouteData.m_startPointIndex, + subrouteData.m_endPointIndex); + if (points.empty()) + return; + std::vector segmentsColors; - segmentsColors.reserve(routeData.m_subroute->m_traffic.size()); - for (auto speedGroup : routeData.m_subroute->m_traffic) + if (!subrouteData.m_subroute->m_traffic.empty()) { - speedGroup = TrafficGenerator::CheckColorsSimplification(speedGroup); - auto const colorConstant = TrafficGenerator::GetColorBySpeedGroup(speedGroup, true /* route */); - dp::Color const color = df::GetColorConstant(colorConstant); - float const alpha = (speedGroup == traffic::SpeedGroup::G4 || - speedGroup == traffic::SpeedGroup::G5 || - speedGroup == traffic::SpeedGroup::Unknown) ? 0.0f : 1.0f; - segmentsColors.emplace_back(color.GetRedF(), color.GetGreenF(), color.GetBlueF(), alpha); + segmentsColors.reserve(subrouteData.m_endPointIndex - subrouteData.m_startPointIndex); + for (size_t i = subrouteData.m_startPointIndex; i < subrouteData.m_endPointIndex; ++i) + { + auto const speedGroup = TrafficGenerator::CheckColorsSimplification(subrouteData.m_subroute->m_traffic[i]); + auto const colorConstant = TrafficGenerator::GetColorBySpeedGroup(speedGroup, true /* route */); + dp::Color const color = df::GetColorConstant(colorConstant); + float const alpha = (speedGroup == traffic::SpeedGroup::G4 || + speedGroup == traffic::SpeedGroup::G5 || + speedGroup == traffic::SpeedGroup::Unknown) ? 0.0f : 1.0f; + segmentsColors.emplace_back(color.GetRedF(), color.GetGreenF(), color.GetBlueF(), alpha); + } } TGeometryBuffer geometry; TGeometryBuffer joinsGeometry; - PrepareGeometry(routeData.m_subroute->m_polyline.GetPoints(), routeData.m_pivot, segmentsColors, - static_cast(routeData.m_subroute->m_baseDepthIndex * kDepthPerSubroute), - geometry, joinsGeometry, routeData.m_length); + PrepareGeometry(points, subrouteData.m_pivot, segmentsColors, + static_cast(subrouteData.m_subroute->m_baseDepthIndex * kDepthPerSubroute), + geometry, joinsGeometry); - auto state = CreateGLState(routeData.m_subroute->m_pattern.m_isDashed ? - gpu::ROUTE_DASH_PROGRAM : gpu::ROUTE_PROGRAM, - RenderState::GeometryLayer); + auto state = CreateGLState(subrouteData.m_subroute->m_style[subrouteData.m_styleIndex].m_pattern.m_isDashed ? + gpu::ROUTE_DASH_PROGRAM : gpu::ROUTE_PROGRAM, RenderState::GeometryLayer); state.SetColorTexture(textures->GetSymbolsTexture()); BatchGeometry(state, make_ref(geometry.data()), static_cast(geometry.size()), make_ref(joinsGeometry.data()), static_cast(joinsGeometry.size()), - RV::GetBindingInfo(), routeData.m_renderProperty); + RV::GetBindingInfo(), subrouteData.m_renderProperty); } void RouteShape::BatchGeometry(dp::GLState const & state, ref_ptr geometry, uint32_t geomSize, @@ -439,7 +446,7 @@ void RouteShape::BatchGeometry(dp::GLState const & state, ref_ptr geometry dp::Batcher batcher(kBatchSize, kBatchSize); dp::SessionGuard guard(batcher, [&property](dp::GLState const & state, drape_ptr && b) { - property.m_buckets.push_back(move(b)); + property.m_buckets.push_back(std::move(b)); property.m_state = state; }); diff --git a/drape_frontend/route_shape.hpp b/drape_frontend/route_shape.hpp index ff3e539f1b..1a604d4066 100644 --- a/drape_frontend/route_shape.hpp +++ b/drape_frontend/route_shape.hpp @@ -39,7 +39,8 @@ enum class RouteType : uint8_t Car, Pedestrian, Bicycle, - Taxi + Taxi, + Transit }; struct RoutePattern @@ -55,18 +56,72 @@ struct RoutePattern , m_dashLength(dashLength) , m_gapLength(gapLength) {} + + bool operator == (RoutePattern const & pattern) const + { + double const kEps = 1e-5; + return m_isDashed == pattern.m_isDashed && + fabs(m_dashLength - pattern.m_dashLength) < kEps && + fabs(m_gapLength - pattern.m_gapLength) < kEps; + } +}; + +enum class SubrouteStyleType +{ + Single = 0, + Multiple +}; + +struct SubrouteStyle +{ + df::ColorConstant m_color; + df::ColorConstant m_outlineColor; + df::RoutePattern m_pattern; + + SubrouteStyle() = default; + SubrouteStyle(df::ColorConstant const & color) + : m_color(color) + , m_outlineColor(color) + {} + SubrouteStyle(df::ColorConstant const & color, df::ColorConstant const & outlineColor) + : m_color(color) + , m_outlineColor(outlineColor) + {} + SubrouteStyle(df::ColorConstant const & color, df::RoutePattern const & pattern) + : m_color(color) + , m_outlineColor(color) + , m_pattern(pattern) + {} + SubrouteStyle(df::ColorConstant const & color, df::ColorConstant const & outlineColor, + df::RoutePattern const & pattern) + : m_color(color) + , m_outlineColor(outlineColor) + , m_pattern(pattern) + {} + + bool operator == (SubrouteStyle const & style) const + { + return m_color == style.m_color && m_outlineColor == style.m_outlineColor && + m_pattern == style.m_pattern; + } + + bool operator != (SubrouteStyle const & style) const + { + return !operator == (style); + } }; struct Subroute { df::RouteType m_routeType; m2::PolylineD m_polyline; - df::ColorConstant m_color; std::vector m_turns; std::vector m_traffic; double m_baseDistance = 0.0; double m_baseDepthIndex = 0.0; - df::RoutePattern m_pattern; + + SubrouteStyleType m_styleType = SubrouteStyleType::Single; + std::vector m_style; }; using SubrouteConstPtr = std::shared_ptr; @@ -80,7 +135,7 @@ struct RouteRenderProperty {} }; -struct BaseRouteData +struct BaseSubrouteData { dp::DrapeID m_subrouteId = 0; m2::PointD m_pivot = m2::PointD(0.0, 0.0); @@ -88,13 +143,15 @@ struct BaseRouteData RouteRenderProperty m_renderProperty; }; -struct RouteData : public BaseRouteData +struct SubrouteData : public BaseSubrouteData { SubrouteConstPtr m_subroute; - double m_length = 0.0; + size_t m_styleIndex = 0; + size_t m_startPointIndex = 0; + size_t m_endPointIndex = 0; }; -struct RouteArrowsData : public BaseRouteData {}; +struct SubrouteArrowsData : public BaseSubrouteData {}; struct ArrowBorders { @@ -111,17 +168,16 @@ public: using AV = gpu::SolidTexturingVertex; using TArrowGeometryBuffer = buffer_vector; - static void CacheRoute(ref_ptr textures, RouteData & routeData); + static void CacheRoute(ref_ptr textures, SubrouteData & subrouteData); static void CacheRouteArrows(ref_ptr mng, m2::PolylineD const & polyline, std::vector const & borders, double baseDepthIndex, - RouteArrowsData & routeArrowsData); + SubrouteArrowsData & routeArrowsData); private: static void PrepareGeometry(std::vector const & path, m2::PointD const & pivot, std::vector const & segmentsColors, float baseDepth, - TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry, - double & outputLength); + TGeometryBuffer & geometry, TGeometryBuffer & joinsGeometry); static void PrepareArrowGeometry(std::vector const & path, m2::PointD const & pivot, m2::RectF const & texRect, float depthStep, float depth, TArrowGeometryBuffer & geometry, diff --git a/geometry/polyline2d.hpp b/geometry/polyline2d.hpp index 4472b218c8..11b3442b0b 100644 --- a/geometry/polyline2d.hpp +++ b/geometry/polyline2d.hpp @@ -128,7 +128,23 @@ public: return vector>(); return reversed ? vector>{m_points[segmentIndex + 1], m_points[segmentIndex]} : - vector>{m_points[segmentIndex], m_points[segmentIndex + 1]}; + vector>{m_points[segmentIndex], m_points[segmentIndex + 1]}; + } + + vector> ExtractSegment(size_t startPointIndex, size_t endPointIndex) const + { + if (startPointIndex > endPointIndex || + startPointIndex + 1 > m_points.size() || + endPointIndex + 1 > m_points.size()) + { + return vector>(); + } + + vector> result; + result.reserve(endPointIndex - startPointIndex + 1); + for (size_t i = startPointIndex; i <= endPointIndex; ++i) + result.push_back(m_points[i]); + return result; } vector > const & GetPoints() const { return m_points; } diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index 9c53e5db7a..11a2a3e218 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -87,6 +87,19 @@ void FillTrafficForRendering(vector const & segments, traffic.push_back(s.GetTraffic()); } +void FillTransitStyleForRendering(vector const & segments, + vector & subrouteStyles) +{ + subrouteStyles.clear(); + subrouteStyles.reserve(segments.size()); + for (auto const & s : segments) + { + // TODO: AddTransitType. + // TODO: Use transit type to determine color and pattern. + subrouteStyles.emplace_back(df::kRoutePedestrian); + } +} + RouteMarkData GetLastPassedPoint(vector const & points) { ASSERT_GREATER_OR_EQUAL(points.size(), 2, ()); @@ -465,29 +478,26 @@ void RoutingManager::InsertRoute(Route const & route) switch (m_currentRouterType) { case RouterType::Vehicle: - subroute->m_routeType = df::RouteType::Car; - subroute->m_color = df::kRouteColor; + case RouterType::Taxi: + subroute->m_routeType = m_currentRouterType == RouterType::Vehicle ? + df::RouteType::Car : df::RouteType::Taxi; + subroute->m_style.emplace_back(df::kRouteColor, df::kRouteOutlineColor); FillTrafficForRendering(segments, subroute->m_traffic); FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, subroute->m_turns); break; + case RouterType::Transit: + subroute->m_routeType = df::RouteType::Transit; + subroute->m_styleType = df::SubrouteStyleType::Multiple; + FillTransitStyleForRendering(segments, subroute->m_style); + break; case RouterType::Pedestrian: - case RouterType::Transit: // TODO: AddTransitType subroute->m_routeType = df::RouteType::Pedestrian; - subroute->m_color = df::kRoutePedestrian; - subroute->m_pattern = df::RoutePattern(4.0, 2.0); + subroute->m_style.emplace_back(df::kRoutePedestrian, df::RoutePattern(4.0, 2.0)); break; case RouterType::Bicycle: subroute->m_routeType = df::RouteType::Bicycle; - subroute->m_color = df::kRouteBicycle; - subroute->m_pattern = df::RoutePattern(8.0, 2.0); - FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, - subroute->m_turns); - break; - case RouterType::Taxi: - subroute->m_routeType = df::RouteType::Taxi; - subroute->m_color = df::kRouteColor; - FillTrafficForRendering(segments, subroute->m_traffic); + subroute->m_style.emplace_back(df::kRouteBicycle, df::RoutePattern(8.0, 2.0)); FillTurnsDistancesForRendering(segments, subroute->m_baseDistance, subroute->m_turns); break;