Rewrite of the ImagingDrawWideLine function

The previous version of the function didn't generate correct wide lines
of even width.

The most notable changes are:
  * Make variable names far more descriptive about the process.
  * Corrected the width calculation; we should deduct one pixel from the
    width because the pixels at the center of the line doesn't count for
    the triangles.
  * Now we calculate *two* ratios, one for left/top displacement (dxmin)
    and one for right/bottom (dxmax), this fix the behavior with lines
    of even width.

It can probably be optimized.
This commit is contained in:
Terseus 2014-04-02 21:30:42 +02:00
parent cd332fc38a
commit be09da6507

View File

@ -588,11 +588,6 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
DRAW* draw; DRAW* draw;
INT32 ink; INT32 ink;
Edge e[4];
int dx, dy;
double d;
DRAWINIT(); DRAWINIT();
if (width <= 1) { if (width <= 1) {
@ -600,23 +595,34 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
return 0; return 0;
} }
dx = x1-x0; int dx = x1-x0;
dy = y1-y0; int dy = y1-y0;
if (dx == 0 && dy == 0) { if (dx == 0 && dy == 0) {
draw->point(im, x0, y0, ink); draw->point(im, x0, y0, ink);
return 0; return 0;
} }
d = width / sqrt((float) (dx*dx + dy*dy)) / 2.0; double big_hypotenuse = sqrt((double) (dx*dx + dy*dy));
double small_hypotenuse = (width - 1) / 2.0;
double ratio_max = ROUND_UP(small_hypotenuse) / big_hypotenuse;
double ratio_min = ROUND_DOWN(small_hypotenuse) / big_hypotenuse;
dx = (int) floor(d * (y1-y0) + 0.5); int dxmin = ROUND_DOWN(ratio_min * dy);
dy = (int) floor(d * (x1-x0) + 0.5); int dxmax = ROUND_DOWN(ratio_max * dy);
int dymin = ROUND_DOWN(ratio_min * dx);
int dymax = ROUND_DOWN(ratio_max * dx);
int vertices[4][2] = {
{x0 - dxmin, y0 + dymax},
{x1 - dxmin, y1 + dymax},
{x1 + dxmax, y1 - dymin},
{x0 + dxmax, y0 - dymin}
};
add_edge(e+0, x0 - dx, y0 + dy, x1 - dx, y1 + dy); Edge e[4];
add_edge(e+1, x1 - dx, y1 + dy, x1 + dx, y1 - dy); add_edge(e+0, vertices[0][0], vertices[0][1], vertices[1][0], vertices[1][1]);
add_edge(e+2, x1 + dx, y1 - dy, x0 + dx, y0 - dy); add_edge(e+1, vertices[1][0], vertices[1][1], vertices[2][0], vertices[2][1]);
add_edge(e+3, x0 + dx, y0 - dy, x0 - dx, y0 + dy); add_edge(e+2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
add_edge(e+3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
draw->polygon(im, 4, e, ink, 0); draw->polygon(im, 4, e, ink, 0);