fix: graph jitter on load + format
This commit is contained in:
+47
-53
@@ -383,7 +383,8 @@ Centering detectCentering(QQuickItem* item) {
|
||||
}
|
||||
if (ad->usedAnchors & QQuickAnchors::VCenterAnchor) {
|
||||
c.vertical = true;
|
||||
c.source += (c.source.isEmpty() ? "" : " ") + QStringLiteral("vCenter");
|
||||
c.source +=
|
||||
(c.source.isEmpty() ? "" : " ") + QStringLiteral("vCenter");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,9 +411,9 @@ Centering detectCentering(QQuickItem* item) {
|
||||
|
||||
// Parity (mod 2) of an item's whole-device-pixel size; no item = even.
|
||||
int devParity(const QQuickItem* it, qreal dpr, bool horizontal) {
|
||||
if (!it)
|
||||
return 0;
|
||||
const qint64 dev = std::llround((horizontal ? it->width() : it->height()) * dpr);
|
||||
if (!it) return 0;
|
||||
const qint64 dev =
|
||||
std::llround((horizontal ? it->width() : it->height()) * dpr);
|
||||
return static_cast<int>(dev % 2);
|
||||
}
|
||||
|
||||
@@ -423,9 +424,9 @@ int devParity(const QQuickItem* it, qreal dpr, bool horizontal) {
|
||||
// since edges = parentLeft + (parentSize - size) / 2.
|
||||
qreal snapToParity(qreal value, qreal dpr, int parity, int mode) {
|
||||
const double exact = value * dpr;
|
||||
qint64 n = mode > 0 ? std::llround(std::ceil(exact - 1e-6))
|
||||
: mode < 0 ? std::llround(std::floor(exact + 1e-6))
|
||||
: std::llround(exact);
|
||||
qint64 n = mode > 0 ? std::llround(std::ceil(exact - 1e-6))
|
||||
: mode < 0 ? std::llround(std::floor(exact + 1e-6))
|
||||
: std::llround(exact);
|
||||
if (static_cast<int>(n % 2) != parity) {
|
||||
if (mode > 0) {
|
||||
++n;
|
||||
@@ -436,8 +437,7 @@ qreal snapToParity(qreal value, qreal dpr, int parity, int mode) {
|
||||
n = (exact >= static_cast<double>(n)) ? n + 1 : n - 1;
|
||||
}
|
||||
}
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
if (n < 0) n = 0;
|
||||
return static_cast<qreal>(n) / dpr;
|
||||
}
|
||||
|
||||
@@ -452,16 +452,17 @@ qint64 roundAway(double value) {
|
||||
// divides exactly), so with the parent's half at a whole device offset the
|
||||
// child's device size must be even; if the parent's half sits on a half device
|
||||
// pixel, the child's device size must be odd instead.
|
||||
qreal snapCenteredSize(qreal value, qreal dpr, qint64 parentHalfRounded, int mode) {
|
||||
qreal snapCenteredSize(
|
||||
qreal value, qreal dpr, qint64 parentHalfRounded, int mode) {
|
||||
const double exact = value * dpr;
|
||||
const double anchorDev = double(parentHalfRounded) * dpr;
|
||||
const bool anchorWhole =
|
||||
std::fabs(anchorDev - std::round(anchorDev)) < 1e-6;
|
||||
const bool anchorWhole = std::fabs(anchorDev - std::round(anchorDev)) <
|
||||
1e-6;
|
||||
const qint64 parity = anchorWhole ? 0 : 1;
|
||||
|
||||
qint64 base = mode > 0 ? std::llround(std::ceil(exact - 1e-6))
|
||||
: mode < 0 ? std::llround(std::floor(exact + 1e-6))
|
||||
: std::llround(exact);
|
||||
qint64 base = mode > 0 ? std::llround(std::ceil(exact - 1e-6))
|
||||
: mode < 0 ? std::llround(std::floor(exact + 1e-6))
|
||||
: std::llround(exact);
|
||||
for (qint64 step = 0; step < 8; ++step) {
|
||||
if (base + step >= 0 && (base + step) % 2 == parity)
|
||||
return qreal(base + step) / dpr;
|
||||
@@ -483,7 +484,8 @@ qreal snapCenteredAxis(
|
||||
int mode) {
|
||||
QQuickItem* parent = item->parentItem();
|
||||
if (!centering.alignWhenCentered && parent) {
|
||||
const qreal parentSize = horizontal ? parent->width() : parent->height();
|
||||
const qreal parentSize = horizontal ? parent->width()
|
||||
: parent->height();
|
||||
return snapCenteredSize(value, dpr, roundAway(parentSize / 2.0), mode);
|
||||
}
|
||||
return snapToParity(value, dpr, devParity(parent, dpr, horizontal), mode);
|
||||
@@ -495,10 +497,8 @@ qreal ZUtils::snap(qreal value, QQuickItem* item) {
|
||||
const qreal dpr = dprFor(item);
|
||||
if (item) {
|
||||
const Centering c = detectCentering(item);
|
||||
if (c.horizontal)
|
||||
return snapCenteredAxis(value, item, dpr, true, c, 0);
|
||||
if (c.vertical)
|
||||
return snapCenteredAxis(value, item, dpr, false, c, 0);
|
||||
if (c.horizontal) return snapCenteredAxis(value, item, dpr, true, c, 0);
|
||||
if (c.vertical) return snapCenteredAxis(value, item, dpr, false, c, 0);
|
||||
}
|
||||
return std::round(value * dpr) / dpr;
|
||||
}
|
||||
@@ -507,10 +507,8 @@ qreal ZUtils::snapCeil(qreal value, QQuickItem* item) {
|
||||
const qreal dpr = dprFor(item);
|
||||
if (item) {
|
||||
const Centering c = detectCentering(item);
|
||||
if (c.horizontal)
|
||||
return snapCenteredAxis(value, item, dpr, true, c, 1);
|
||||
if (c.vertical)
|
||||
return snapCenteredAxis(value, item, dpr, false, c, 1);
|
||||
if (c.horizontal) return snapCenteredAxis(value, item, dpr, true, c, 1);
|
||||
if (c.vertical) return snapCenteredAxis(value, item, dpr, false, c, 1);
|
||||
}
|
||||
return std::ceil(value * dpr - 1e-6) / dpr;
|
||||
}
|
||||
@@ -521,8 +519,7 @@ qreal ZUtils::snapFloor(qreal value, QQuickItem* item) {
|
||||
const Centering c = detectCentering(item);
|
||||
if (c.horizontal)
|
||||
return snapCenteredAxis(value, item, dpr, true, c, -1);
|
||||
if (c.vertical)
|
||||
return snapCenteredAxis(value, item, dpr, false, c, -1);
|
||||
if (c.vertical) return snapCenteredAxis(value, item, dpr, false, c, -1);
|
||||
}
|
||||
return std::floor(value * dpr + 1e-6) / dpr;
|
||||
}
|
||||
@@ -568,15 +565,12 @@ bool ZUtils::logPlacement(QQuickItem* item, const QString& tag) {
|
||||
// instead of dividing, so the edges are what matter.
|
||||
const auto centeredAxisOk = [&](double lo, double hi) {
|
||||
const double size = hi - lo;
|
||||
if (isOff(size))
|
||||
return false;
|
||||
if (!c.alignWhenCentered)
|
||||
return !isOff(lo) && !isOff(hi);
|
||||
if (isOff(size)) return false;
|
||||
if (!c.alignWhenCentered) return !isOff(lo) && !isOff(hi);
|
||||
const double center = (lo + hi) / 2.0;
|
||||
const double parity = (std::llround(size) % 2 == 0) ? 0.0 : 0.5;
|
||||
double err = std::fmod(center - parity, 1.0);
|
||||
if (err < 0)
|
||||
err += 1.0;
|
||||
if (err < 0) err += 1.0;
|
||||
return std::min(err, 1.0 - err) <= tol;
|
||||
};
|
||||
|
||||
@@ -605,9 +599,7 @@ bool ZUtils::logPlacement(QQuickItem* item, const QString& tag) {
|
||||
<< "\n device px: left=" << fmt(l) << " top=" << fmt(t)
|
||||
<< " right=" << fmt(rt) << " bottom=" << fmt(b)
|
||||
<< (isText ? " (right/bottom ignored: Text)" : "")
|
||||
<< (!centerSrc.isEmpty()
|
||||
? " (centered: " + centerSrc + ")"
|
||||
: QString())
|
||||
<< (!centerSrc.isEmpty() ? " (centered: " + centerSrc + ")" : QString())
|
||||
<< (centeredH || centeredV
|
||||
? QString("\n center: x=%1 y=%2 size=%3 x %4")
|
||||
.arg(QString::number((l + rt) / 2, 'f', 2))
|
||||
@@ -642,8 +634,8 @@ bool ZUtils::logCurvePlacement(
|
||||
constexpr double tol = 1e-3;
|
||||
|
||||
const double dpr = dprFor(item);
|
||||
const int devW = static_cast<int>(
|
||||
std::max<qint64>(1, std::llround(lineWidth * dpr)));
|
||||
const int devW =
|
||||
static_cast<int>(std::max<qint64>(1, std::llround(lineWidth * dpr)));
|
||||
const double half = devW / 2.0;
|
||||
|
||||
qsizetype offCount = 0;
|
||||
@@ -690,23 +682,25 @@ bool ZUtils::logCurvePlacement(
|
||||
const qsizetype flat = total - sloped;
|
||||
const bool aligned = offCount == 0;
|
||||
|
||||
qInfo().noquote()
|
||||
<< (aligned ? "[CURVE ALIGNED] " : "[CURVE UNALIGNED]")
|
||||
<< (tag.isEmpty() ? QString::fromUtf8(item->metaObject()->className())
|
||||
: tag)
|
||||
<< "\n samples: " << total << " points (" << flat << " flat, "
|
||||
<< sloped << " sloped ignored), dpr=" << dpr
|
||||
<< ", stroke width=" << lineWidth << " logical = " << devW
|
||||
<< " device px"
|
||||
<< "\n edges: " << offCount << " of " << flat * 2
|
||||
<< " flat stroke edges off the device grid";
|
||||
qInfo().noquote() << (aligned ? "[CURVE ALIGNED] " : "[CURVE UNALIGNED]")
|
||||
<< (tag.isEmpty() ? QString::fromUtf8(
|
||||
item->metaObject()->className())
|
||||
: tag)
|
||||
<< "\n samples: " << total << " points (" << flat
|
||||
<< " flat, " << sloped << " sloped ignored), dpr=" << dpr
|
||||
<< ", stroke width=" << lineWidth << " logical = " << devW
|
||||
<< " device px"
|
||||
<< "\n edges: " << offCount << " of " << flat * 2
|
||||
<< " flat stroke edges off the device grid";
|
||||
if (!aligned) {
|
||||
qInfo().noquote()
|
||||
<< " worst: deviation=" << QString::number(worst, 'f', 3)
|
||||
<< " device px at logical x=" << QString::number(worstX, 'f', 2)
|
||||
<< " y=" << QString::number(worstY, 'f', 2)
|
||||
<< " (" << (worstSide < 0 ? "top" : "bottom") << " edge device="
|
||||
<< QString::number(worstEdge, 'f', 3) << ")";
|
||||
qInfo().noquote() << " worst: deviation="
|
||||
<< QString::number(worst, 'f', 3)
|
||||
<< " device px at logical x="
|
||||
<< QString::number(worstX, 'f', 2)
|
||||
<< " y=" << QString::number(worstY, 'f', 2) << " ("
|
||||
<< (worstSide < 0 ? "top" : "bottom")
|
||||
<< " edge device="
|
||||
<< QString::number(worstEdge, 'f', 3) << ")";
|
||||
}
|
||||
|
||||
return aligned;
|
||||
|
||||
Reference in New Issue
Block a user