fix: stroke arcs and splines analytically — opaque core, angle-independent weight
LICE_Arc never reaches opacity and ThickFLine's width is minor-axis. One distance-to-polyline coverage mask, blended once, replaces both.
This commit is contained in:
@@ -25,18 +25,30 @@ double valuePerPixel(const VelocityCurve::Box& box, CurveDomain d) {
|
||||
if (h <= 1) return 0.0;
|
||||
return (kCurveYMax - curveYMin(d)) / static_cast<double>(h - 1);
|
||||
}
|
||||
int velToX(const VelocityCurve::Box& box, double velocity) {
|
||||
// The integer maps are these rounded — ONE mapping, so a sub-pixel trace and an integer hit-test
|
||||
// cannot drift. Rounding the OFFSET (not the absolute coordinate) keeps the int results identical
|
||||
// to what they were before the sub-pixel form existed: the offset is non-negative, so truncation
|
||||
// is floor regardless of where the box sits.
|
||||
double velToXf(const VelocityCurve::Box& box, double velocity) {
|
||||
const int w = std::max(0, box.width);
|
||||
if (w <= 0) return box.left;
|
||||
if (w <= 0) return static_cast<double>(box.left);
|
||||
const double frac = (clampVelocity(velocity) - kVelMin) / (kVelMax - kVelMin);
|
||||
return box.left + static_cast<int>(frac * static_cast<double>(w) + 0.5);
|
||||
return static_cast<double>(box.left) + frac * static_cast<double>(w);
|
||||
}
|
||||
int valueToY(const VelocityCurve::Box& box, double value, CurveDomain d) {
|
||||
double valueToYf(const VelocityCurve::Box& box, double value, CurveDomain d) {
|
||||
const int h = std::max(0, box.height);
|
||||
if (h <= 1) return box.top;
|
||||
if (h <= 1) return static_cast<double>(box.top);
|
||||
const double lo = curveYMin(d);
|
||||
const double frac = (clampValue(value, d) - lo) / (kCurveYMax - lo);
|
||||
return box.top + static_cast<int>((1.0 - frac) * static_cast<double>(h - 1) + 0.5);
|
||||
return static_cast<double>(box.top) + (1.0 - frac) * static_cast<double>(h - 1);
|
||||
}
|
||||
int velToX(const VelocityCurve::Box& box, double velocity) {
|
||||
return box.left +
|
||||
static_cast<int>(velToXf(box, velocity) - static_cast<double>(box.left) + 0.5);
|
||||
}
|
||||
int valueToY(const VelocityCurve::Box& box, double value, CurveDomain d) {
|
||||
return box.top +
|
||||
static_cast<int>(valueToYf(box, value, d) - static_cast<double>(box.top) + 0.5);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -187,6 +199,11 @@ VelocityCurve::CurvePixel VelocityCurve::pixelFromPoint(const Box& box,
|
||||
return CurvePixel{velToX(box, p.velocity), valueToY(box, p.value, domain_)};
|
||||
}
|
||||
|
||||
VelocityCurve::CurvePixelF VelocityCurve::subpixelFromPoint(const Box& box,
|
||||
const VelocityPoint& p) const {
|
||||
return CurvePixelF{velToXf(box, p.velocity), valueToYf(box, p.value, domain_)};
|
||||
}
|
||||
|
||||
VelocityPoint VelocityCurve::pointFromPixel(const Box& box, int x, int y) const {
|
||||
// Exact inverse of velToX/valueToY (within one pixel); degenerate dims collapse the same way.
|
||||
VelocityPoint p;
|
||||
|
||||
Reference in New Issue
Block a user