mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
statistics: don't place labels at half-integer values
Placing labels at half-integer values gives horrible rendering artifacts. Therefore, always round to integer values. The easiest way to do this is right before setting the position. Introduce a helper function to round QPointF in such scenarios. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
f1203d365a
commit
5b6f468547
7 changed files with 31 additions and 12 deletions
|
|
@ -143,6 +143,7 @@ SOURCES += subsurface-mobile-main.cpp \
|
||||||
stats/statsaxis.cpp \
|
stats/statsaxis.cpp \
|
||||||
stats/statscolors.cpp \
|
stats/statscolors.cpp \
|
||||||
stats/statsgrid.cpp \
|
stats/statsgrid.cpp \
|
||||||
|
stats/statshelper.cpp \
|
||||||
stats/statsseries.cpp \
|
stats/statsseries.cpp \
|
||||||
stats/statsstate.cpp \
|
stats/statsstate.cpp \
|
||||||
mobile-widgets/qmlinterface.cpp \
|
mobile-widgets/qmlinterface.cpp \
|
||||||
|
|
@ -295,6 +296,7 @@ HEADERS += \
|
||||||
stats/statsaxis.h \
|
stats/statsaxis.h \
|
||||||
stats/statscolors.h \
|
stats/statscolors.h \
|
||||||
stats/statsgrid.h \
|
stats/statsgrid.h \
|
||||||
|
stats/statshelper.h \
|
||||||
stats/statsseries.h \
|
stats/statsseries.h \
|
||||||
stats/statsstate.h \
|
stats/statsstate.h \
|
||||||
stats/statstranslations.h \
|
stats/statstranslations.h \
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ set(SUBSURFACE_STATS_SRCS
|
||||||
statscolors.cpp
|
statscolors.cpp
|
||||||
statsgrid.h
|
statsgrid.h
|
||||||
statsgrid.cpp
|
statsgrid.cpp
|
||||||
|
statshelper.h
|
||||||
|
statshelper.cpp
|
||||||
statsseries.h
|
statsseries.h
|
||||||
statsseries.cpp
|
statsseries.cpp
|
||||||
statsstate.h
|
statsstate.h
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ void BarSeries::BarLabel::updatePosition(bool horizontal, bool center, const QRe
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QPointF pos = rect.center();
|
QPointF pos = rect.center();
|
||||||
pos.rx() -= round(itemSize.width() / 2.0);
|
pos.rx() -= itemSize.width() / 2.0;
|
||||||
|
|
||||||
// Heuristics: if the label fits nicely into the bar (bar height is at least twice the label height),
|
// Heuristics: if the label fits nicely into the bar (bar height is at least twice the label height),
|
||||||
// then put the label in the middle of the bar. Otherwise, put it at the top of the bar.
|
// then put the label in the middle of the bar. Otherwise, put it at the top of the bar.
|
||||||
|
|
@ -130,29 +130,29 @@ void BarSeries::BarLabel::updatePosition(bool horizontal, bool center, const QRe
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pos.ry() -= round(itemSize.height() / 2.0);
|
pos.ry() -= itemSize.height() / 2.0;
|
||||||
}
|
}
|
||||||
item->setPos(pos);
|
item->setPos(roundPos(pos)); // Round to integer to avoid ugly artifacts.
|
||||||
} else {
|
} else {
|
||||||
if (itemSize.height() > rect.height()) {
|
if (itemSize.height() > rect.height()) {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QPointF pos = rect.center();
|
QPointF pos = rect.center();
|
||||||
pos.ry() -= round(itemSize.height() / 2.0);
|
pos.ry() -= itemSize.height() / 2.0;
|
||||||
|
|
||||||
// Heuristics: if the label fits nicely into the bar (bar width is at least twice the label height),
|
// Heuristics: if the label fits nicely into the bar (bar width is at least twice the label height),
|
||||||
// then put the label in the middle of the bar. Otherwise, put it to the right of the bar.
|
// then put the label in the middle of the bar. Otherwise, put it to the right of the bar.
|
||||||
isOutside = !center && rect.width() < 2.0 * itemSize.width();
|
isOutside = !center && rect.width() < 2.0 * itemSize.width();
|
||||||
if (isOutside) {
|
if (isOutside) {
|
||||||
pos.rx() = round(rect.right() + 2.0); // Leave two pixels(?) space
|
pos.rx() = rect.right() + 2.0; // Leave two pixels(?) space
|
||||||
} else {
|
} else {
|
||||||
if (itemSize.width() > rect.width()) {
|
if (itemSize.width() > rect.width()) {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item->setPos(pos);
|
item->setPos(roundPos(pos)); // Round to integer to avoid ugly artifacts.
|
||||||
}
|
}
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
// If label changed from inside to outside, or vice-versa, the color might change.
|
// If label changed from inside to outside, or vice-versa, the color might change.
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,9 @@ void PieSeries::Item::updatePositions(const QPointF ¢er, double radius)
|
||||||
// because half-integer values gives horrible aliasing artifacts.
|
// because half-integer values gives horrible aliasing artifacts.
|
||||||
if (innerLabel) {
|
if (innerLabel) {
|
||||||
QRectF labelRect = innerLabel->getRect();
|
QRectF labelRect = innerLabel->getRect();
|
||||||
innerLabel->setPos(QPointF(round(center.x() + innerLabelPos.x() * radius - labelRect.width() / 2.0),
|
QPointF pos(center.x() + innerLabelPos.x() * radius - labelRect.width() / 2.0,
|
||||||
round(center.y() + innerLabelPos.y() * radius - labelRect.height() / 2.0)));
|
center.y() + innerLabelPos.y() * radius - labelRect.height() / 2.0);
|
||||||
|
innerLabel->setPos(roundPos(pos));
|
||||||
}
|
}
|
||||||
if (outerLabel) {
|
if (outerLabel) {
|
||||||
QRectF labelRect = outerLabel->getRect();
|
QRectF labelRect = outerLabel->getRect();
|
||||||
|
|
@ -59,7 +60,7 @@ void PieSeries::Item::updatePositions(const QPointF ¢er, double radius)
|
||||||
pos.ry() -= labelRect.height();
|
pos.ry() -= labelRect.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
outerLabel->setPos(QPointF(round(pos.x()), round(pos.y())));
|
outerLabel->setPos(roundPos(pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
stats/statshelper.cpp
Normal file
10
stats/statshelper.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#include "statshelper.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
QPointF roundPos(const QPointF &p)
|
||||||
|
{
|
||||||
|
return QPointF(round(p.x()), round(p.y()));
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Helper functions to render the stats. Currently contains
|
// Helper functions to render the stats. Includes
|
||||||
// QSGNode template jugglery to overcome API flaws.
|
// QSGNode template jugglery to overcome API flaws.
|
||||||
#ifndef STATSHELPER_H
|
#ifndef STATSHELPER_H
|
||||||
#define STATSHELPER_H
|
#define STATSHELPER_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <QPointF>
|
||||||
#include <QSGNode>
|
#include <QSGNode>
|
||||||
|
|
||||||
|
// Round positions to integer values to avoid ugly artifacts
|
||||||
|
QPointF roundPos(const QPointF &p);
|
||||||
|
|
||||||
// A stupid pointer class that initializes to null and can be copy
|
// A stupid pointer class that initializes to null and can be copy
|
||||||
// assigned. This is for historical reasons: unique_ptrs to ChartItems
|
// assigned. This is for historical reasons: unique_ptrs to ChartItems
|
||||||
// were replaced by plain pointers. Instead of nulling the plain pointers
|
// were replaced by plain pointers. Instead of nulling the plain pointers
|
||||||
|
|
|
||||||
|
|
@ -397,8 +397,8 @@ void StatsView::updateTitlePos()
|
||||||
{
|
{
|
||||||
if (!title)
|
if (!title)
|
||||||
return;
|
return;
|
||||||
title->setPos(QPointF(round(sceneBorder + (boundingRect().width() - title->getRect().width()) / 2.0),
|
QPointF pos(sceneBorder + (boundingRect().width() - title->getRect().width()) / 2.0, sceneBorder);
|
||||||
round(sceneBorder)));
|
title->setPos(roundPos(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, class... Args>
|
template <typename T, class... Args>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue