13
0

Fix mouse events on clamped automation lines

This fixes the following problem:
When automation lines with significant change are zoomed in time, the
slope gets smaller (towards horizontal) as the control points moves
further away from the visible area. That was rendered correctly, but the
corresponding mouse events happened as if the line had a steeper slope.

The problem was caused by the X value being clamped to the visible area,
without scaling the Y value correspondingly. It has apparently been like
that for a decode, since introduced in c4f0063a68.

The problem is fixed by introducing a clamp2 function that scales the Y
value if clamping the X value.

Note: An old comment says that math goes wrong unless clamping below
COORD_MAX. It is not clear to me what math it refers to, and especially
why we don't need similar clamping on the lower bounds.

And while rarely a real problem, I guess it would be more correct and a
slight optimization to skip all lines where both ends are outside the
same bound. In theory, as it is now, the mouse could catch an invisible
line close to the border.
This commit is contained in:
Mads Kiilerich 2022-10-04 14:42:55 +02:00 committed by Robin Gareus
parent 056a79bfb6
commit d1265b5a02
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -121,6 +121,24 @@ PolyLine::set_steps (Points const& points, bool stepped)
PolyItem::set (copy);
}
// Clamp x1 to xmax, and scale y1 accordingly, relative to (x0,y0)
static void
clamp2 (double& x1, double& y1, double x0, double y0, double xmax) {
if (x1 > xmax) {
double dx = x1 - x0;
double dy = y1 - y0;
double slope = 0;
// only compute slope if relevant (and safe without overflow / division by zero);
// the line is on the xmax edge, and barely visible since x1 is far out and dx is small
if (fabs(dx) > 0.1) {
slope = dy / dx;
}
x1 = xmax;
double new_dx = x1 - x0;
y1 = y0 + new_dx * slope;
}
}
bool
PolyLine::covers (Duple const& point) const
{
@ -151,10 +169,10 @@ PolyLine::covers (Duple const& point) const
math goes wrong.
*/
a.x = std::min (a.x, visible.x1);
a.y = std::min (a.y, visible.y1);
b.x = std::min (b.x, visible.x1);
b.y = std::min (b.y, visible.y1);
clamp2 (a.x, a.y, b.x, b.y, visible.x1);
clamp2 (a.y, a.x, b.y, b.x, visible.y1);
clamp2 (b.x, b.y, a.x, a.y, visible.x1);
clamp2 (b.y, b.x, a.y, a.x, visible.y1);
double d = distance_to_segment_squared (p, a, b, t, at);