From 181017b90d8153724b7ed75f76509f979d51fe7e Mon Sep 17 00:00:00 2001 From: ExMix Date: Tue, 6 Jan 2015 11:58:47 +0300 Subject: [drape] path text adaptation --- drape_frontend/apply_feature_functors.cpp | 2 +- drape_frontend/path_symbol_shape.cpp | 4 +- drape_frontend/path_text_shape.cpp | 216 ++++++++++-------------------- drape_frontend/path_text_shape.hpp | 2 +- drape_frontend/text_layout.cpp | 100 ++++++++++++-- drape_frontend/text_layout.hpp | 50 ++++--- geometry/geometry_tests/spline_test.cpp | 52 +++---- geometry/spline.cpp | 121 ++++++++++++----- geometry/spline.hpp | 10 +- 9 files changed, 312 insertions(+), 245 deletions(-) diff --git a/drape_frontend/apply_feature_functors.cpp b/drape_frontend/apply_feature_functors.cpp index 913a1ad07f..4a4897a33e 100644 --- a/drape_frontend/apply_feature_functors.cpp +++ b/drape_frontend/apply_feature_functors.cpp @@ -357,7 +357,7 @@ void ApplyLineFeature::Finish() while (!it.BeginAgain()) { m_context.InsertShape(m_tileKey, dp::MovePointer(new TextShape(it.m_pos, viewParams))); - it.Step(splineStep); + it.Advance(splineStep); } } } diff --git a/drape_frontend/path_symbol_shape.cpp b/drape_frontend/path_symbol_shape.cpp index ddc8b9ded5..f4535c9936 100644 --- a/drape_frontend/path_symbol_shape.cpp +++ b/drape_frontend/path_symbol_shape.cpp @@ -36,7 +36,7 @@ void PathSymbolShape::Draw(dp::RefPointer batcher, dp::RefPointer batcher, dp::RefPointerGetGlyphCount()); } void Update(ScreenBase const & screen) { - m_scalePtoG = screen.GetScale(); - GetBegEnd(m_begin, m_end); - - SetIsValid(!m_begin.BeginAgain() && !m_end.BeginAgain()); - if (!IsValid()) + if (m_layout->CacheDynamicGeometry(m_centerPointIter, screen, m_normals)) + { + SetIsValid(true); return; + } - if (screen.GtoP(m_end.m_pos).x < screen.GtoP(m_begin.m_pos).x) - m_isForward = false; - else - m_isForward = true; + SetIsValid(false); } m2::RectD GetPixelRect(ScreenBase const & screen) const { ASSERT(IsValid(), ()); - ASSERT(!m_begin.BeginAgain(), ()); - ASSERT(!m_end.BeginAgain(), ()); - - AccumulateRect f(screen); - m_spline->ForEachNode(m_begin, m_end, f); - float const pixelHeight = m_layout->GetPixelHeight(); - f.m_pixelRect.Inflate(2 * pixelHeight, 2 * pixelHeight); - return f.m_pixelRect; - } + m2::PointD pixelPivot(screen.GtoP(m_centerPointIter.m_pos)); + m2::RectD result; + for (gpu::TextDynamicVertex const & v : m_normals) + result.Add(pixelPivot + glsl::ToPoint(v.m_normal)); + + return result; + } void GetPixelShape(ScreenBase const & screen, Rects & rects) const { - rects = m_bboxes; + ASSERT(IsValid(), ()); + + m2::PointD pixelPivot(screen.GtoP(m_centerPointIter.m_pos)); + for (size_t quadIndex = 0; quadIndex < m_normals.size(); quadIndex += 4) + { + m2::RectF r; + r.Add(pixelPivot + glsl::ToPoint(m_normals[quadIndex].m_normal)); + r.Add(pixelPivot + glsl::ToPoint(m_normals[quadIndex + 1].m_normal)); + r.Add(pixelPivot + glsl::ToPoint(m_normals[quadIndex + 2].m_normal)); + r.Add(pixelPivot + glsl::ToPoint(m_normals[quadIndex + 3].m_normal)); + rects.push_back(r); + } } void GetAttributeMutation(dp::RefPointer mutator, ScreenBase const & screen) const { ASSERT(IsValid(), ()); - uint32_t byteCount = 4 * m_layout->GetGlyphCount() * sizeof(glsl::vec2); - void * buffer = mutator->AllocateMutationBuffer(byteCount); - df::IntrusiveVector positions(buffer, byteCount); - // m_splineOffset set offset to Center of text. - // By this we calc offset for start of text in mercator - m_layout->LayoutPathText(m_begin, m_scalePtoG, positions, m_isForward, m_bboxes, screen); - TOffsetNode const & node = GetOffsetNode(PathGlyphPositionID); + TOffsetNode const & node = GetOffsetNode(gpu::TextDynamicVertex::GetDynamicStreamID()); + ASSERT(node.first.GetElementSize() == sizeof(gpu::TextDynamicVertex), ()); + ASSERT(node.second.m_count == m_normals.size(), ()); + + uint32_t byteCount = m_normals.size() * sizeof(gpu::TextDynamicVertex); + void * buffer = mutator->AllocateMutationBuffer(byteCount); + memcpy(buffer, m_normals.data(), byteCount); dp::MutateNode mutateNode; mutateNode.m_region = node.second; - mutateNode.m_data = dp::MakeStackRefPointer(buffer); + mutateNode.m_data = dp::MakeStackRefPointer(buffer); mutator->AddMutation(node.first, mutateNode); } - private: - void GetBegEnd(Spline::iterator & beg, Spline::iterator & end) const - { - beg = m_spline.CreateIterator(); - end = m_spline.CreateIterator(); - float const textLength = m_layout->GetPixelLength() * m_scalePtoG; - float const step = max(0.0f, m_splineOffset - textLength / 2.0f); - if (step > 0.0f) - beg.Step(step); - end.Step(step + textLength); - } - private: m2::SharedSpline m_spline; - m2::Spline::iterator m_begin; - m2::Spline::iterator m_end; - mutable Rects m_bboxes; + m2::Spline::iterator m_centerPointIter; + gpu::TTextDynamicVertexBuffer m_normals; df::SharedTextLayout m_layout; - float m_scalePtoG; - float m_splineOffset; - bool m_isForward; }; - - void BatchPathText(m2::SharedSpline const & spline, - buffer_vector const & offsets, - float depth, - dp::RefPointer batcher, - df::SharedTextLayout const & layout, - vector & positions, - vector & texCoord, - vector & fontColor, - vector & index, - dp::RefPointer textures) - { - ASSERT(!offsets.empty(), ()); - layout->InitPathText(depth, texCoord, fontColor, index, textures); - - dp::GLState state(gpu::PATH_FONT_PROGRAM, dp::GLState::OverlayLayer); - state.SetTextureSet(layout->GetTextureSet()); - state.SetBlending(dp::Blending(true)); - - for (size_t i = 0; i < offsets.size(); ++i) - { - dp::AttributeProvider provider(4, 4 * layout->GetGlyphCount()); - { - dp::BindingInfo positionBind(1, PathTextHandle::PathGlyphPositionID); - dp::BindingDecl & decl = positionBind.GetBindingDecl(0); - decl.m_attributeName = "a_position"; - decl.m_componentCount = 2; - decl.m_componentType = gl_const::GLFloatType; - decl.m_offset = 0; - decl.m_stride = 0; - provider.InitStream(0, positionBind, dp::MakeStackRefPointer(&positions[0])); - } - { - dp::BindingInfo texCoordBind(1); - dp::BindingDecl & decl = texCoordBind.GetBindingDecl(0); - decl.m_attributeName = "a_texcoord"; - decl.m_componentCount = 4; - decl.m_componentType = gl_const::GLFloatType; - decl.m_offset = 0; - decl.m_stride = 0; - provider.InitStream(1, texCoordBind, dp::MakeStackRefPointer(&texCoord[0])); - } - { - dp::BindingInfo fontColorBind(1); - dp::BindingDecl & decl = fontColorBind.GetBindingDecl(0); - decl.m_attributeName = "a_color"; - decl.m_componentCount = 4; - decl.m_componentType = gl_const::GLFloatType; - decl.m_offset = 0; - decl.m_stride = 0; - provider.InitStream(2, fontColorBind, dp::MakeStackRefPointer(&fontColor[0])); - } - { - dp::BindingInfo outlineColorBind(1); - dp::BindingDecl & decl = outlineColorBind.GetBindingDecl(0); - decl.m_attributeName = "a_index"; - decl.m_componentCount = 1; - decl.m_componentType = gl_const::GLFloatType; - decl.m_offset = 0; - decl.m_stride = 0; - provider.InitStream(3, outlineColorBind, dp::MakeStackRefPointer(&index[0])); - } - - dp::OverlayHandle * handle = new PathTextHandle(spline, layout, offsets[i], depth); - batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), dp::MovePointer(handle), 4); - } - } } namespace df @@ -210,11 +115,11 @@ PathTextShape::PathTextShape(m2::SharedSpline const & spline, { } -void PathTextShape::Draw(dp::RefPointer batcher, dp::RefPointer textures) const +void PathTextShape::Draw(dp::RefPointer batcher, dp::RefPointer textures) const { - SharedTextLayout layout(new TextLayout(strings::MakeUniString(m_params.m_text), - m_params.m_textFont, - textures)); + PathTextLayout * layout = new PathTextLayout(strings::MakeUniString(m_params.m_text), + m_params.m_textFont.m_size, + textures); uint32_t glyphCount = layout->GetGlyphCount(); if (glyphCount == 0) @@ -239,10 +144,6 @@ void PathTextShape::Draw(dp::RefPointer batcher, dp::RefPointer positions(glyphCount, glsl::vec2(0.0, 0.0)); - vector texCoords(glyphCount); - vector fontColor(glyphCount); - vector index(glyphCount); buffer_vector offsets; float const scalePtoG = 1.0f / m_params.m_baseGtoPScale; @@ -278,8 +179,39 @@ void PathTextShape::Draw(dp::RefPointer batcher, dp::RefPointerGetColorRegion(m_params.m_textFont.m_color, color); + textures->GetColorRegion(m_params.m_textFont.m_outlineColor, outline); + + dp::GLState state(gpu::TEXT_PROGRAM, dp::GLState::OverlayLayer); + state.SetBlending(dp::Blending(true)); + state.SetColorTexture(color.GetTexture()); + state.SetMaskTexture(layout->GetMaskTexture()); + + ASSERT(!offsets.empty(), ()); + gpu::TTextStaticVertexBuffer staticBuffer; + gpu::TTextDynamicVertexBuffer dynBuffer; + SharedTextLayout layoutPtr(layout); + for (float offset : offsets) + { + staticBuffer.clear(); + dynBuffer.clear(); + + Spline::iterator iter = m_spline.CreateIterator(); + iter.Advance(offset); + layout->CacheStaticGeometry(glsl::vec3(glsl::ToVec2(iter.m_pos), m_params.m_depth), + color, outline, staticBuffer); + + dynBuffer.resize(staticBuffer.size(), gpu::TextDynamicVertex(glsl::vec2(0.0, 0.0))); + + dp::AttributeProvider provider(2, staticBuffer.size()); + provider.InitStream(0, gpu::TextStaticVertex::GetBindingInfo(), dp::MakeStackRefPointer(staticBuffer.data())); + provider.InitStream(1, gpu::TextDynamicVertex::GetBindingInfo(), dp::MakeStackRefPointer(dynBuffer.data())); + + dp::OverlayHandle * handle = new PathTextHandle(m_spline, layoutPtr, offset, m_params.m_depth); + batcher->InsertListOfStrip(state, dp::MakeStackRefPointer(&provider), dp::MovePointer(handle), 4); + } } } diff --git a/drape_frontend/path_text_shape.hpp b/drape_frontend/path_text_shape.hpp index 3468665cca..9612a9ea80 100644 --- a/drape_frontend/path_text_shape.hpp +++ b/drape_frontend/path_text_shape.hpp @@ -13,7 +13,7 @@ class PathTextShape : public MapShape public: PathTextShape(m2::SharedSpline const & spline, PathTextViewParams const & params); - virtual void Draw(dp::RefPointer batcher, dp::RefPointer textures) const; + virtual void Draw(dp::RefPointer batcher, dp::RefPointer textures) const; private: m2::SharedSpline m_spline; diff --git a/drape_frontend/text_layout.cpp b/drape_frontend/text_layout.cpp index a477bbe30b..1b177b6f68 100644 --- a/drape_frontend/text_layout.cpp +++ b/drape_frontend/text_layout.cpp @@ -16,6 +16,7 @@ namespace { float const BASE_HEIGHT = 20.0f; +float const VALID_SPLINE_TURN = 0.96f; class TextGeometryGenerator { @@ -70,9 +71,7 @@ public: void operator()(dp::TextureManager::GlyphRegion const & glyph) { - m2::PointU pixelSize(m2::PointU::Zero()); - glyph.GetPixelSize(pixelSize); - pixelSize *= m_textRatio; + m2::PointF pixelSize = m2::PointF(glyph.GetPixelSize()) * m_textRatio; float const xOffset = glyph.GetOffsetX() * m_textRatio; float const yOffset = glyph.GetOffsetY() * m_textRatio; @@ -251,11 +250,6 @@ void CalculateOffsets(dp::Anchor anchor, } // namespace -TextLayout::TextLayout(df::TextLayout::LayoutType type) - : m_type(type) -{ -} - void TextLayout::Init(strings::UniString const & text, float fontSize, dp::RefPointer textures) { @@ -295,7 +289,6 @@ float TextLayout::GetPixelHeight() const StraightTextLayout::StraightTextLayout(strings::UniString const & text, float fontSize, dp::RefPointer textures, dp::Anchor anchor) - : TBase(TextLayout::LayoutType::StraightLayout) { strings::UniString visibleText = fribidi::log2vis(text); buffer_vector delimIndexes; @@ -327,8 +320,84 @@ void StraightTextLayout::Cache(glm::vec3 const & pivot, glm::vec2 const & pixelO } } +PathTextLayout::PathTextLayout(strings::UniString const & text, float fontSize, + dp::RefPointer textures) +{ + Init(fribidi::log2vis(text), fontSize, textures); +} + +void PathTextLayout::CacheStaticGeometry(glm::vec3 const & pivot, + dp::TextureManager::ColorRegion const & colorRegion, + dp::TextureManager::ColorRegion const & outlineRegion, + gpu::TTextStaticVertexBuffer & staticBuffer) const +{ + TextGeometryGenerator gen(pivot, colorRegion, outlineRegion, staticBuffer); + for_each(m_metrics.begin(), m_metrics.end(), gen); +} + +bool PathTextLayout::CacheDynamicGeometry(m2::Spline::iterator const & iter, ScreenBase const & screen, + gpu::TTextDynamicVertexBuffer & buffer) const +{ + float const scalePtoG = screen.GetScale(); + float const glbHalfLength = 0.5 * GetPixelLength() * scalePtoG; + + m2::Spline::iterator beginIter = iter; + beginIter.Advance(-glbHalfLength); + m2::Spline::iterator endIter = iter; + endIter.Advance(glbHalfLength); + if (beginIter.BeginAgain() || endIter.BeginAgain()) + return false; + + float const halfFontSize = 0.5 * GetPixelHeight(); + float advanceSign = 1.0f; + m2::Spline::iterator penIter = beginIter; + if (screen.GtoP(beginIter.m_pos).x > screen.GtoP(endIter.m_pos).x) + { + advanceSign = -advanceSign; + penIter = endIter; + } + + glsl::vec2 pxPivot = glsl::ToVec2(screen.GtoP(iter.m_pos)); + buffer.resize(4 * m_metrics.size()); + for (size_t i = 0; i < m_metrics.size(); ++i) + { + GlyphRegion const & g = m_metrics[i]; + m2::PointF pxSize = m2::PointF(g.GetPixelSize()) * m_textSizeRatio; + + m2::PointD const pxBase = screen.GtoP(penIter.m_pos); + m2::PointD const pxShiftBase = screen.GtoP(penIter.m_pos + penIter.m_dir); + + glsl::vec2 tangent = advanceSign * glsl::normalize(glsl::ToVec2(pxShiftBase - pxBase)); + glsl::vec2 normal = glsl::normalize(glsl::vec2(-tangent.y, tangent.x)); + glsl::vec2 formingVector = (glsl::ToVec2(pxBase) - pxPivot) + (halfFontSize * normal); + + float const xOffset = g.GetOffsetX() * m_textSizeRatio; + float const yOffset = g.GetOffsetY() * m_textSizeRatio; + + float const upVector = - (pxSize.y + yOffset); + float const bottomVector = - yOffset; + + size_t baseIndex = 4 * i; + + buffer[baseIndex + 0] = gpu::TextDynamicVertex(formingVector + normal * upVector + tangent * xOffset); + buffer[baseIndex + 1] = gpu::TextDynamicVertex(formingVector + normal * bottomVector + tangent * xOffset); + buffer[baseIndex + 2] = gpu::TextDynamicVertex(formingVector + normal * upVector + tangent * (pxSize.x + xOffset)); + buffer[baseIndex + 3] = gpu::TextDynamicVertex(formingVector + normal * bottomVector + tangent * (pxSize.x + xOffset)); + + + float const xAdvance = g.GetAdvanceX() * m_textSizeRatio; + glsl::vec2 currentTangent = glsl::ToVec2(penIter.m_dir); + penIter.Advance(advanceSign * xAdvance * scalePtoG); + float const dotProduct = glsl::dot(currentTangent, glsl::ToVec2(penIter.m_dir)); + if (dotProduct < VALID_SPLINE_TURN) + return false; + } + + return true; +} + /////////////////////////////////////////////////////////////// -SharedTextLayout::SharedTextLayout(TextLayout * layout) +SharedTextLayout::SharedTextLayout(PathTextLayout * layout) : m_layout(layout) { } @@ -338,17 +407,22 @@ bool SharedTextLayout::IsNull() const return m_layout == NULL; } -void SharedTextLayout::Reset(TextLayout * layout) +void SharedTextLayout::Reset(PathTextLayout * layout) { m_layout.reset(layout); } -TextLayout * SharedTextLayout::operator->() +PathTextLayout * SharedTextLayout::GetRaw() +{ + return m_layout.get(); +} + +PathTextLayout * SharedTextLayout::operator->() { return m_layout.get(); } -TextLayout const * SharedTextLayout::operator->() const +PathTextLayout const * SharedTextLayout::operator->() const { return m_layout.get(); } diff --git a/drape_frontend/text_layout.hpp b/drape_frontend/text_layout.hpp index ea98ac636f..e5e1e8410c 100644 --- a/drape_frontend/text_layout.hpp +++ b/drape_frontend/text_layout.hpp @@ -29,11 +29,7 @@ class TextLayout { public: - enum class LayoutType - { - StraightLayout, - PathLayout - }; + virtual ~TextLayout() {} dp::RefPointer GetMaskTexture() const; @@ -41,23 +37,17 @@ public: float GetPixelLength() const; float GetPixelHeight() const; - LayoutType GetType() const { return m_type; } protected: - TextLayout(LayoutType type); void Init(strings::UniString const & text, float fontSize, dp::RefPointer textures); - protected: typedef dp::TextureManager::GlyphRegion GlyphRegion; dp::TextureManager::TGlyphsBuffer m_metrics; float m_textSizeRatio = 0.0; - -private: - LayoutType m_type; }; class StraightTextLayout : public TextLayout @@ -69,11 +59,11 @@ public: dp::RefPointer textures, dp::Anchor anchor); - void Cache(glm::vec3 const & pivot, glsl::vec2 const & pixelOffset, - dp::TextureManager::ColorRegion const & colorRegion, - dp::TextureManager::ColorRegion const & outlineRegion, - gpu::TTextStaticVertexBuffer & staticBuffer, - gpu::TTextDynamicVertexBuffer & dynamicBuffer) const; + void Cache(glsl::vec3 const & pivot, glsl::vec2 const & pixelOffset, + dp::TextureManager::ColorRegion const & colorRegion, + dp::TextureManager::ColorRegion const & outlineRegion, + gpu::TTextStaticVertexBuffer & staticBuffer, + gpu::TTextDynamicVertexBuffer & dynamicBuffer) const; m2::PointU const & GetPixelSize() const { return m_pixelSize; } @@ -82,19 +72,37 @@ private: m2::PointU m_pixelSize; }; +class PathTextLayout : public TextLayout +{ + typedef TextLayout TBase; +public: + PathTextLayout(strings::UniString const & text, + float fontSize, dp::RefPointer textures); + + void CacheStaticGeometry(glsl::vec3 const & pivot, + dp::TextureManager::ColorRegion const & colorRegion, + dp::TextureManager::ColorRegion const & outlineRegion, + gpu::TTextStaticVertexBuffer & staticBuffer) const; + + bool CacheDynamicGeometry(m2::Spline::iterator const & iter, + ScreenBase const & screen, + gpu::TTextDynamicVertexBuffer & buffer) const; +}; + class SharedTextLayout { public: - SharedTextLayout(TextLayout * layout); + SharedTextLayout(PathTextLayout * layout); bool IsNull() const; - void Reset(TextLayout * layout); + void Reset(PathTextLayout * layout); + PathTextLayout * GetRaw(); - TextLayout * operator->(); - TextLayout const * operator->() const; + PathTextLayout * operator->(); + PathTextLayout const * operator->() const; private: - shared_ptr m_layout; + shared_ptr m_layout; }; } diff --git a/geometry/geometry_tests/spline_test.cpp b/geometry/geometry_tests/spline_test.cpp index 6f70967732..d901340583 100644 --- a/geometry/geometry_tests/spline_test.cpp +++ b/geometry/geometry_tests/spline_test.cpp @@ -28,11 +28,11 @@ UNIT_TEST(SmoothedDirections) PointD dir2(sqrt2 / 2.0, -sqrt2 / 2.0); itr.Attach(spl); TestPointDDir(itr.m_avrDir, dir1); - itr.Step(sqrt2 * 30.0); + itr.Advance(sqrt2 * 30.0); TestPointDDir(itr.m_avrDir, dir1); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_avrDir, dir1 * 0.25 + dir2 * 0.75); - itr.Step(sqrt2 * 10.0); + itr.Advance(sqrt2 * 10.0); TestPointDDir(itr.m_avrDir, dir2); path.clear(); @@ -46,12 +46,12 @@ UNIT_TEST(SmoothedDirections) Spline spl2(path); itr.Attach(spl2); TestPointDDir(itr.m_avrDir, dir1); - itr.Step(sqrt2 * 80.0 + 40.0); + itr.Advance(sqrt2 * 80.0 + 40.0); TestPointDDir(itr.m_avrDir, dir12); itr.Attach(spl2); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_avrDir, dir1); - itr.Step(80.0); + itr.Advance(80.0); TestPointDDir(itr.m_avrDir, dir12 * 0.5 + dir2 * 0.5); } @@ -69,9 +69,9 @@ UNIT_TEST(UsualDirections) PointD dir2(sqrt2 / 2.0, -sqrt2 / 2.0); itr.Attach(spl); TestPointDDir(itr.m_dir, dir1); - itr.Step(sqrt2 * 30.0); + itr.Advance(sqrt2 * 30.0); TestPointDDir(itr.m_dir, dir1); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_dir, dir2); path.clear(); @@ -85,12 +85,12 @@ UNIT_TEST(UsualDirections) Spline spl2(path); itr.Attach(spl2); TestPointDDir(itr.m_dir, dir1); - itr.Step(sqrt2 * 80.0 + 35.0); + itr.Advance(sqrt2 * 80.0 + 35.0); TestPointDDir(itr.m_dir, dir2); itr.Attach(spl2); - itr.Step(sqrt2 * 45.0); + itr.Advance(sqrt2 * 45.0); TestPointDDir(itr.m_dir, dir12); - itr.Step(80.0); + itr.Advance(80.0); TestPointDDir(itr.m_dir, dir2); } @@ -108,15 +108,15 @@ UNIT_TEST(Positions) Spline::iterator itr; itr.Attach(spl0); TestPointDDir(itr.m_pos, PointD(0, 0)); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_pos, PointD(40, 40)); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_pos, PointD(80, 0)); itr.Attach(spl4); TestPointDDir(itr.m_pos, PointD(0, 0)); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_pos, PointD(40, 40)); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_pos, PointD(80, 0)); path.clear(); @@ -130,16 +130,16 @@ UNIT_TEST(Positions) Spline spl3 = spl2; itr.Attach(spl3); TestPointDDir(itr.m_pos, PointD(0, 0)); - itr.Step(sqrt2 * 80.0 + 40.0); + itr.Advance(sqrt2 * 80.0 + 40.0); TestPointDDir(itr.m_pos, PointD(120, 0)); itr.Attach(spl2); - itr.Step(sqrt2 * 40.0); + itr.Advance(sqrt2 * 40.0); TestPointDDir(itr.m_pos, PointD(40, 40)); - itr.Step(2.0); + itr.Advance(2.0); TestPointDDir(itr.m_pos, PointD(42, 40)); - itr.Step(20.0); + itr.Advance(20.0); TestPointDDir(itr.m_pos, PointD(62, 40)); - itr.Step(18.0); + itr.Advance(18.0); TestPointDDir(itr.m_pos, PointD(80, 40)); } @@ -157,11 +157,11 @@ UNIT_TEST(BeginAgain) PointD dir2(sqrt2 / 2.0, -sqrt2 / 2.0); itr.Attach(spl); TEST_EQUAL(itr.BeginAgain(), false, ()); - itr.Step(90.0); + itr.Advance(90.0); TEST_EQUAL(itr.BeginAgain(), false, ()); - itr.Step(90.0); + itr.Advance(90.0); TEST_EQUAL(itr.BeginAgain(), true, ()); - itr.Step(190.0); + itr.Advance(190.0); TEST_EQUAL(itr.BeginAgain(), true, ()); path.clear(); @@ -174,11 +174,11 @@ UNIT_TEST(BeginAgain) Spline spl2(path); itr.Attach(spl2); TEST_EQUAL(itr.BeginAgain(), false, ()); - itr.Step(90.0); + itr.Advance(90.0); TEST_EQUAL(itr.BeginAgain(), false, ()); - itr.Step(90.0); + itr.Advance(90.0); TEST_EQUAL(itr.BeginAgain(), true, ()); - itr.Step(190.0); + itr.Advance(190.0); TEST_EQUAL(itr.BeginAgain(), true, ()); } diff --git a/geometry/spline.cpp b/geometry/spline.cpp index 1a2df1b5d3..1f2048f1a4 100644 --- a/geometry/spline.cpp +++ b/geometry/spline.cpp @@ -76,6 +76,34 @@ Spline::iterator::iterator() , m_index(0) , m_dist(0) {} +Spline::iterator::iterator(Spline::iterator const & other) +{ + m_checker = other.m_checker; + m_spl = other.m_spl; + m_index = other.m_index; + m_dist = other.m_dist; + + m_pos = other.m_pos; + m_dir = other.m_dir; + m_avrDir = other.m_avrDir; +} + +Spline::iterator & Spline::iterator::operator=(Spline::iterator const & other) +{ + if (this == &other) + return *this; + + m_checker = other.m_checker; + m_spl = other.m_spl; + m_index = other.m_index; + m_dist = other.m_dist; + + m_pos = other.m_pos; + m_dir = other.m_dir; + m_avrDir = other.m_avrDir; + return *this; +} + void Spline::iterator::Attach(Spline const & spl) { m_spl = &spl; @@ -87,44 +115,12 @@ void Spline::iterator::Attach(Spline const & spl) m_pos = m_spl->m_position[m_index] + m_dir * m_dist; } -void Spline::iterator::Step(double speed) -{ - m_dist += speed; - if (m_checker) - { - m_pos = m_spl->m_position[m_index] + m_dir * m_dist; - return; - } - while (m_dist > m_spl->m_length[m_index]) - { - m_dist -= m_spl->m_length[m_index]; - m_index++; - if (m_index >= m_spl->m_direction.size()) - { - m_index--; - m_dist += m_spl->m_length[m_index]; - m_checker = true; - break; - } - } - m_dir = m_spl->m_direction[m_index]; - m_avrDir = -m_pos; - m_pos = m_spl->m_position[m_index] + m_dir * m_dist; - m_avrDir += m_pos; -} - -void Spline::iterator::StepBack(double speed) +void Spline::iterator::Advance(double step) { - m_dist -= speed; - while(m_dist < 0.0f) - { - m_index--; - m_dist += m_spl->m_length[m_index]; - } - m_dir = m_spl->m_direction[m_index]; - m_avrDir = -m_pos; - m_pos = m_spl->m_position[m_index] + m_dir * m_dist; - m_avrDir += m_pos; + if (step < 0.0) + AdvanceBackward(step); + else + AdvanceForward(step); } double Spline::iterator::GetLength() const @@ -152,6 +148,57 @@ int Spline::iterator::GetIndex() const return m_index; } +void Spline::iterator::AdvanceBackward(double step) +{ + m_dist += step; + while(m_dist < 0.0f) + { + m_index--; + if (m_index < 0) + { + m_index = 0; + m_checker = true; + m_pos = m_spl->m_position[m_index]; + m_dir = m_spl->m_direction[m_index]; + m_avrDir = m2::PointD::Zero(); + m_dist = 0.0; + return; + } + + m_dist += m_spl->m_length[m_index]; + } + m_dir = m_spl->m_direction[m_index]; + m_avrDir = -m_pos; + m_pos = m_spl->m_position[m_index] + m_dir * m_dist; + m_avrDir += m_pos; +} + +void Spline::iterator::AdvanceForward(double step) +{ + m_dist += step; + if (m_checker) + { + m_pos = m_spl->m_position[m_index] + m_dir * m_dist; + return; + } + while (m_dist > m_spl->m_length[m_index]) + { + m_dist -= m_spl->m_length[m_index]; + m_index++; + if (m_index >= m_spl->m_direction.size()) + { + m_index--; + m_dist += m_spl->m_length[m_index]; + m_checker = true; + break; + } + } + m_dir = m_spl->m_direction[m_index]; + m_avrDir = -m_pos; + m_pos = m_spl->m_position[m_index] + m_dir * m_dist; + m_avrDir += m_pos; +} + SharedSpline::SharedSpline(vector const & path) { m_spline.reset(new Spline(path)); diff --git a/geometry/spline.hpp b/geometry/spline.hpp index d313968ae3..12c5c77e79 100644 --- a/geometry/spline.hpp +++ b/geometry/spline.hpp @@ -17,10 +17,13 @@ public: PointD m_pos; PointD m_dir; PointD m_avrDir; + iterator(); + iterator(iterator const & other); + iterator & operator=(iterator const & other); + void Attach(Spline const & spl); - void Step(double speed); - void StepBack(double speed); + void Advance(double step); bool BeginAgain() const; double GetLength() const; double GetFullLength() const; @@ -30,6 +33,9 @@ public: double GetDistance() const; int GetIndex() const; + void AdvanceForward(double step); + void AdvanceBackward(double step); + private: bool m_checker; Spline const * m_spl; -- cgit v1.2.3