Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify and fix kerning of curved text #4006

Merged
merged 1 commit into from
Dec 14, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 34 additions & 66 deletions src/core/StelPainter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,84 +575,52 @@ void StelPainter::sSphereMap(double radius, unsigned int slices, unsigned int st
}
}

void StelPainter::drawTextGravity180(float x, float y, const QString& ws, float xshift, float yshift)
void StelPainter::drawTextGravity180(const float x, const float y, const QString& ws, const float xshift, const float yshift)
{
const float dx = x - static_cast<float>(prj->viewportCenter[0]);
const float dy = y - static_cast<float>(prj->viewportCenter[1]);
const float d = std::sqrt(dx*dx + dy*dy);
const float limit = 120.;
float d = std::sqrt(dx*dx + dy*dy);

// If the text is too far away to be visible in the screen return
if (d>qMax(prj->viewportXywh[3], prj->viewportXywh[2])*2 || ws.isEmpty())
return;

const auto fm = getFontMetrics();
const bool rtl = StelApp::getInstance().getLocaleMgr().isSkyRTL();

const float ppx = static_cast<float>(prj->getDevicePixelsPerPixel());
const float cWidth = static_cast<float>(getFontMetrics().boundingRect(ws).width())/ws.length(); // average character width
const float stdWidth = static_cast<float>(getFontMetrics().boundingRect("n").width());
const float theta_o = M_PIf + std::atan2(dx, dy - 1);
float anglePerUnitWidth = ppx / d;
float theta = std::atan2(dy - 1, dx);
float psi = std::atan2(ppx*cWidth*1.2, d + 1) * M_180_PIf; // Factor 1.2 is empirical.
if (psi>5)
psi = 5;

const float xVc = static_cast<float>(prj->viewportCenter[0]) + xshift;
const float yVc = static_cast<float>(prj->viewportCenter[1]) + yshift;
const float cosr = std::cos(-theta_o * M_PI_180f);
const float sinr = std::sin(-theta_o * M_PI_180f);
float xom = x + xshift*cosr - yshift*sinr;
float yom = y + yshift*sinr + xshift*cosr;
float width;
QChar s;

if (!StelApp::getInstance().getLocaleMgr().isSkyRTL())
{
for (int i=0; i<ws.length(); ++i)
{
s = ws[i];
if (d<limit)
{
drawText(xom, yom, s, -theta_o*M_180_PIf+psi*static_cast<float>(i), 0., 0.);
xom += cWidth*std::cos(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
yom += cWidth*std::sin(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
}
else
{
x = d * std::cos(theta) + xVc ;
y = d * std::sin(theta) + yVc ;
drawText(x, y, s, 90.f + theta*M_180_PIf, 0., 0.);
// Compute how much the character contributes to the angle
if (s.isSpace())
width = stdWidth;
else
width = static_cast<float>(getFontMetrics().boundingRect(s).width());
theta += psi * M_PI_180f * (1 + (width - cWidth)/ cWidth);
}
}

float xVc = static_cast<float>(prj->viewportCenter[0]) + xshift;
float yVc = static_cast<float>(prj->viewportCenter[1]) + yshift;

const float charWidth = fm.averageCharWidth();
constexpr float maxAnglePerChar = 10 * M_PI_180f;
if (charWidth * anglePerUnitWidth > maxAnglePerChar)
{
// Too curvy text, limit its curvature by moving the center of curvature away
const float x0 = d * std::cos(theta) + xVc;
const float y0 = d * std::sin(theta) + yVc;

anglePerUnitWidth = maxAnglePerChar / charWidth;
d = ppx / anglePerUnitWidth;

xVc = x0 - d * std::cos(theta);
yVc = y0 - d * std::sin(theta);
}
else

const int slen = ws.length();
const int startI = rtl ? slen - 1 : 0;
const int endI = rtl ? -1 : slen;
const int inc = rtl ? -1 : 1;
for (int i = startI; i != endI; i += inc)
{
int slen = ws.length();
for (int i=0;i<slen;i++)
{
s = ws[slen-1-i];
if (d<limit)
{
drawText(xom, yom, s, -theta_o*M_180_PIf+psi*static_cast<float>(i), 0., 0.);
xom += cWidth*std::cos(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
yom += cWidth*std::sin(-theta_o+psi*static_cast<float>(i) * M_PI_180f);
}
else
{
x = d * std::cos(theta) + xVc;
y = d * std::sin(theta) + yVc;
drawText(x, y, s, 90.f + theta*M_180_PIf, 0., 0.);
if (s.isSpace())
width = stdWidth;
else
width = static_cast<float>(getFontMetrics().boundingRect(s).width());
theta += psi * M_PI_180f * (1 + (width - cWidth)/ cWidth);
}
}
const QChar c = ws[i];
const float x = d * std::cos(theta) + xVc;
const float y = d * std::sin(theta) + yVc;
drawText(x, y, c, 90.f + theta*M_180_PIf, 0., 0.);
theta += fm.horizontalAdvance(c) * anglePerUnitWidth;
}
}

Expand Down
Loading