From 87a7658b5789d07f9403a966532440ce026787a6 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 14 Dec 2013 23:30:39 +0100 Subject: [PATCH] Improve gdispDrawThickLine() when the line length is short. --- src/gdisp/gdisp.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 03d84ca9..8af496b3 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -2587,18 +2587,39 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co /* Normalize the normal vector to length width. * This uses Newton-Raphson to avoid the need for floating point sqrt. - * We try to solve f(div) = div^2 - len/width^2. + * We try to solve f(div) = div^2 - len/width^2 = 0. + * The closed-form solution is div = sqrt(len) / width. */ { int32_t div, len, tmp; uint8_t i; - len = nx*nx + ny*ny; + len = (int32_t)nx*nx + (int32_t)ny*ny; div = 100; /* Initial guess for divider; not critical */ + /* If the line length is quite short, premultiply the vector + * in order to get better accuracy in width. */ + if (len < 1024) + { + nx <<= 8; + ny <<= 8; + len <<= 16; + } + else if (len < 65536) + { + nx <<= 4; + ny <<= 4; + len <<= 8; + } + + int prev = div; for (i = 0; i < 5; i++) { tmp = width * width * div; div -= (tmp * div - len) / (2 * tmp); + + if (div == prev) + break; // No change, iteration complete + prev = div; } nx = rounding_div(nx, div);