Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
263
libs/drape_frontend/line_shape_helper.cpp
Normal file
263
libs/drape_frontend/line_shape_helper.cpp
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
#include "drape_frontend/line_shape_helper.hpp"
|
||||
|
||||
#include "drape/glsl_func.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void UpdateNormalBetweenSegments(LineSegment * segment1, LineSegment * segment2)
|
||||
{
|
||||
ASSERT(segment1 != nullptr && segment2 != nullptr, ());
|
||||
|
||||
float const dotProduct = glsl::dot(segment1->m_leftNormals[EndPoint], segment2->m_leftNormals[StartPoint]);
|
||||
float const absDotProduct = fabs(dotProduct);
|
||||
float constexpr kEps = 1e-5;
|
||||
|
||||
if (fabs(absDotProduct - 1.0f) < kEps)
|
||||
{
|
||||
// change nothing
|
||||
return;
|
||||
}
|
||||
|
||||
float constexpr kMaxScalar = 5;
|
||||
float const crossProduct = glsl::cross(glsl::vec3(segment1->m_tangent, 0), glsl::vec3(segment2->m_tangent, 0)).z;
|
||||
if (crossProduct < 0)
|
||||
{
|
||||
segment1->m_hasLeftJoin[EndPoint] = true;
|
||||
segment2->m_hasLeftJoin[StartPoint] = true;
|
||||
|
||||
// change right-side normals
|
||||
glsl::vec2 averageNormal =
|
||||
glsl::normalize(segment1->m_rightNormals[EndPoint] + segment2->m_rightNormals[StartPoint]);
|
||||
float const cosAngle = glsl::dot(segment1->m_tangent, averageNormal);
|
||||
float const widthScalar = 1.0f / sqrt(1.0f - cosAngle * cosAngle);
|
||||
if (widthScalar < kMaxScalar)
|
||||
{
|
||||
segment1->m_rightNormals[EndPoint] = averageNormal;
|
||||
segment2->m_rightNormals[StartPoint] = averageNormal;
|
||||
segment1->m_rightWidthScalar[EndPoint].x = widthScalar;
|
||||
segment1->m_rightWidthScalar[EndPoint].y = widthScalar * cosAngle;
|
||||
segment2->m_rightWidthScalar[StartPoint] = segment1->m_rightWidthScalar[EndPoint];
|
||||
}
|
||||
else
|
||||
{
|
||||
segment1->m_generateJoin = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
segment1->m_hasLeftJoin[EndPoint] = false;
|
||||
segment2->m_hasLeftJoin[StartPoint] = false;
|
||||
|
||||
// change left-side normals
|
||||
glsl::vec2 averageNormal = glsl::normalize(segment1->m_leftNormals[EndPoint] + segment2->m_leftNormals[StartPoint]);
|
||||
float const cosAngle = glsl::dot(segment1->m_tangent, averageNormal);
|
||||
float const widthScalar = 1.0f / sqrt(1.0f - cosAngle * cosAngle);
|
||||
if (widthScalar < kMaxScalar)
|
||||
{
|
||||
segment1->m_leftNormals[EndPoint] = averageNormal;
|
||||
segment2->m_leftNormals[StartPoint] = averageNormal;
|
||||
segment1->m_leftWidthScalar[EndPoint].x = widthScalar;
|
||||
segment1->m_leftWidthScalar[EndPoint].y = widthScalar * cosAngle;
|
||||
segment2->m_leftWidthScalar[StartPoint] = segment1->m_leftWidthScalar[EndPoint];
|
||||
}
|
||||
else
|
||||
{
|
||||
segment1->m_generateJoin = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void CalculateTangentAndNormals(glsl::vec2 const & pt0, glsl::vec2 const & pt1, glsl::vec2 & tangent,
|
||||
glsl::vec2 & leftNormal, glsl::vec2 & rightNormal)
|
||||
{
|
||||
tangent = glsl::normalize(pt1 - pt0);
|
||||
leftNormal = glsl::vec2(-tangent.y, tangent.x);
|
||||
rightNormal = -leftNormal;
|
||||
}
|
||||
|
||||
void ConstructLineSegments(std::vector<m2::PointD> const & path, std::vector<glsl::vec4> const & segmentsColors,
|
||||
std::vector<LineSegment> & segments)
|
||||
{
|
||||
ASSERT_LESS(1, path.size(), ());
|
||||
|
||||
if (!segmentsColors.empty())
|
||||
ASSERT_EQUAL(segmentsColors.size() + 1, path.size(), ());
|
||||
|
||||
m2::PointD prevPoint = path[0];
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
m2::PointF const p1 = m2::PointF(prevPoint.x, prevPoint.y);
|
||||
m2::PointF const p2 = m2::PointF(path[i].x, path[i].y);
|
||||
if (p1.EqualDxDy(p2, 1.0E-5))
|
||||
continue;
|
||||
|
||||
// Important! Do emplace_back first and fill parameters later.
|
||||
// Fill parameters first and push_back later will cause ugly bug in clang 3.6 -O3 optimization.
|
||||
segments.emplace_back(glsl::ToVec2(p1), glsl::ToVec2(p2));
|
||||
LineSegment & segment = segments.back();
|
||||
|
||||
CalculateTangentAndNormals(glsl::ToVec2(p1), glsl::ToVec2(p2), segment.m_tangent, segment.m_leftBaseNormal,
|
||||
segment.m_rightBaseNormal);
|
||||
|
||||
segment.m_leftNormals[StartPoint] = segment.m_leftNormals[EndPoint] = segment.m_leftBaseNormal;
|
||||
segment.m_rightNormals[StartPoint] = segment.m_rightNormals[EndPoint] = segment.m_rightBaseNormal;
|
||||
if (!segmentsColors.empty())
|
||||
segment.m_color = segmentsColors[i - 1];
|
||||
|
||||
prevPoint = path[i];
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateNormals(LineSegment * segment, LineSegment * prevSegment, LineSegment * nextSegment)
|
||||
{
|
||||
ASSERT(segment != nullptr, ());
|
||||
|
||||
if (prevSegment != nullptr)
|
||||
UpdateNormalBetweenSegments(prevSegment, segment);
|
||||
|
||||
if (nextSegment != nullptr)
|
||||
UpdateNormalBetweenSegments(segment, nextSegment);
|
||||
}
|
||||
|
||||
std::vector<glsl::vec2> GenerateJoinNormals(dp::LineJoin joinType, glsl::vec2 const & normal1,
|
||||
glsl::vec2 const & normal2, float halfWidth, bool isLeft, float widthScalar,
|
||||
std::vector<glsl::vec2> * uv)
|
||||
{
|
||||
std::vector<glsl::vec2> normals;
|
||||
float const eps = 1e-5;
|
||||
if (fabs(glsl::dot(normal1, normal2) - 1.0f) < eps)
|
||||
return normals;
|
||||
|
||||
if (joinType == dp::LineJoin::BevelJoin)
|
||||
{
|
||||
glsl::vec2 const n1 = halfWidth * normal1;
|
||||
glsl::vec2 const n2 = halfWidth * normal2;
|
||||
|
||||
normals = {glsl::vec2(0.0f, 0.0f), isLeft ? n1 : n2, isLeft ? n2 : n1};
|
||||
|
||||
if (uv)
|
||||
{
|
||||
*uv = {glsl::vec2(0.5f, 0.5f), isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f),
|
||||
isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f)};
|
||||
}
|
||||
}
|
||||
else if (joinType == dp::LineJoin::MiterJoin)
|
||||
{
|
||||
glsl::vec2 averageNormal = halfWidth * widthScalar * glsl::normalize(normal1 + normal2);
|
||||
|
||||
glsl::vec2 const n1 = halfWidth * normal1;
|
||||
glsl::vec2 const n2 = halfWidth * normal2;
|
||||
|
||||
normals = {glsl::vec2(0.0f, 0.0f), isLeft ? n1 : averageNormal, isLeft ? averageNormal : n1,
|
||||
glsl::vec2(0.0f, 0.0f), isLeft ? averageNormal : n2, isLeft ? n2 : averageNormal};
|
||||
|
||||
if (uv)
|
||||
{
|
||||
*uv = {glsl::vec2(0.5f, 0.5f),
|
||||
isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f),
|
||||
isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f),
|
||||
|
||||
glsl::vec2(0.5f, 0.5f),
|
||||
isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f),
|
||||
isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f)};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double const segmentAngle = math::pi / 8.0;
|
||||
double const fullAngle = acos(glsl::dot(normal1, normal2));
|
||||
int segmentsCount = static_cast<int>(fullAngle / segmentAngle);
|
||||
if (segmentsCount == 0)
|
||||
segmentsCount = 1;
|
||||
|
||||
double const angle = fullAngle / segmentsCount * (isLeft ? -1.0 : 1.0);
|
||||
glsl::vec2 const normalizedNormal = glsl::normalize(normal1);
|
||||
m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y);
|
||||
|
||||
normals.reserve(segmentsCount * 3);
|
||||
if (uv)
|
||||
uv->reserve(segmentsCount * 3);
|
||||
|
||||
for (int i = 0; i < segmentsCount; i++)
|
||||
{
|
||||
m2::PointD n1 = m2::Rotate(startNormal, i * angle) * halfWidth;
|
||||
m2::PointD n2 = m2::Rotate(startNormal, (i + 1) * angle) * halfWidth;
|
||||
|
||||
normals.push_back(glsl::vec2(0.0f, 0.0f));
|
||||
normals.push_back(isLeft ? glsl::vec2(n1.x, n1.y) : glsl::vec2(n2.x, n2.y));
|
||||
normals.push_back(isLeft ? glsl::vec2(n2.x, n2.y) : glsl::vec2(n1.x, n1.y));
|
||||
|
||||
if (uv)
|
||||
{
|
||||
uv->push_back(glsl::vec2(0.5f, 0.5f));
|
||||
uv->push_back(isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f));
|
||||
uv->push_back(isLeft ? glsl::vec2(0.5f, 0.0f) : glsl::vec2(0.5f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
std::vector<glsl::vec2> GenerateCapNormals(dp::LineCap capType, glsl::vec2 const & normal1, glsl::vec2 const & normal2,
|
||||
glsl::vec2 const & direction, float halfWidth, bool isStart,
|
||||
int segmentsCount)
|
||||
{
|
||||
std::vector<glsl::vec2> normals;
|
||||
if (capType == dp::ButtCap)
|
||||
return normals;
|
||||
|
||||
if (capType == dp::SquareCap)
|
||||
{
|
||||
glsl::vec2 const n1 = halfWidth * normal1;
|
||||
glsl::vec2 const n2 = halfWidth * normal2;
|
||||
glsl::vec2 const n3 = halfWidth * (normal1 + direction);
|
||||
glsl::vec2 const n4 = halfWidth * (normal2 + direction);
|
||||
|
||||
normals = {n2, isStart ? n4 : n1, isStart ? n1 : n4, n1, isStart ? n4 : n3, isStart ? n3 : n4};
|
||||
}
|
||||
else
|
||||
{
|
||||
double const segmentSize = math::pi / segmentsCount * (isStart ? -1.0 : 1.0);
|
||||
glsl::vec2 const normalizedNormal = glsl::normalize(normal2);
|
||||
m2::PointD const startNormal(normalizedNormal.x, normalizedNormal.y);
|
||||
|
||||
normals.reserve(segmentsCount * 3);
|
||||
for (int i = 0; i < segmentsCount; i++)
|
||||
{
|
||||
m2::PointD n1 = m2::Rotate(startNormal, i * segmentSize) * halfWidth;
|
||||
m2::PointD n2 = m2::Rotate(startNormal, (i + 1) * segmentSize) * halfWidth;
|
||||
|
||||
normals.push_back(glsl::vec2(0.0f, 0.0f));
|
||||
normals.push_back(isStart ? glsl::vec2(n1.x, n1.y) : glsl::vec2(n2.x, n2.y));
|
||||
normals.push_back(isStart ? glsl::vec2(n2.x, n2.y) : glsl::vec2(n1.x, n1.y));
|
||||
}
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
glsl::vec2 GetNormal(LineSegment const & segment, bool isLeft, ENormalType normalType)
|
||||
{
|
||||
if (normalType == BaseNormal)
|
||||
return isLeft ? segment.m_leftBaseNormal : segment.m_rightBaseNormal;
|
||||
|
||||
int const index = (normalType == StartNormal) ? StartPoint : EndPoint;
|
||||
return isLeft ? segment.m_leftWidthScalar[index].x * segment.m_leftNormals[index]
|
||||
: segment.m_rightWidthScalar[index].x * segment.m_rightNormals[index];
|
||||
}
|
||||
|
||||
float GetProjectionLength(glsl::vec2 const & newPoint, glsl::vec2 const & startPoint, glsl::vec2 const & endPoint)
|
||||
{
|
||||
glsl::vec2 const v1 = endPoint - startPoint;
|
||||
glsl::vec2 const v2 = newPoint - startPoint;
|
||||
float const squareLen = glsl::dot(v1, v1);
|
||||
float const proj = glsl::dot(v1, v2) / squareLen;
|
||||
return sqrt(squareLen) * math::Clamp(proj, 0.0f, 1.0f);
|
||||
}
|
||||
} // namespace df
|
||||
Loading…
Add table
Add a link
Reference in a new issue