Xiaolin Wu's line algorithm: Difference between revisions

Content added Content deleted
({{header|Racket}} implementation added)
(Updated D entry)
Line 181: Line 181:


/// Plots anti-aliased line by Xiaolin Wu's line algorithm.
/// Plots anti-aliased line by Xiaolin Wu's line algorithm.
void aaLine(Color)(ref Image!Color img, double x1, double y1,
void aaLine(Color)(ref Image!Color img,
double x2, double y2,
double x1, double y1,
in Color color)
double x2, double y2,
/*pure*/ nothrow {
in Color color) /*pure*/ nothrow {
// Straight translation of Wikipedia pseudocode.
// Straight translation of Wikipedia pseudocode.
static double round(in double x) /*pure*/ nothrow {
static double round(in double x) pure nothrow {
return floor(x + 0.5); // Not pure.
return floor(x + 0.5);
}
}


static double fpart(in double x) /*pure*/ nothrow {
static double fpart(in double x) pure nothrow {
return x - floor(x);
return x - x.floor;
}
}


static double rfpart(in double x) /*pure*/ nothrow {
static double rfpart(in double x) pure nothrow {
return 1 - fpart(x);
return 1 - fpart(x);
}
}
Line 200: Line 200:
auto dx = x2 - x1;
auto dx = x2 - x1;
auto dy = y2 - y1;
auto dy = y2 - y1;
immutable ax = abs(dx);
immutable ax = dx.abs;
immutable ay = abs(dy);
immutable ay = dy.abs;


static Color mixColors(in Color c1, in Color c2, in double p)
static Color mixColors(in Color c1, in Color c2, in double p)
Line 215: Line 215:


// Plot function set here to handle the two cases of slope.
// Plot function set here to handle the two cases of slope.
void delegate(in int, in int, in double) nothrow plot;
void delegate(ref Image!Color img, in int, in int, in double)
pure nothrow plot;

if (ax < ay) {
if (ax < ay) {
swap(x1, y1);
swap(x1, y1);
swap(x2, y2);
swap(x2, y2);
swap(dx, dy);
swap(dx, dy);
plot = (x, y, p) {
//plot = (img, x, y, p) {
plot = (ref Image!Color img, x, y, p) {
assert(p >= 0.0 && p <= 1.0);
assert(p >= 0.0 && p <= 1.0);
img[y, x] = mixColors(color, img[y, x], p);
img[y, x] = mixColors(color, img[y, x], p);
};
};
} else {
} else {
plot = (x, y, p) {
//plot = (img, x, y, p) {
plot = (ref Image!Color img, x, y, p) {
assert(p >= 0.0 && p <= 1.0);
assert(p >= 0.0 && p <= 1.0);
img[x, y] = mixColors(color, img[x, y], p);
img[x, y] = mixColors(color, img[x, y], p);
Line 238: Line 242:


// Handle first endpoint.
// Handle first endpoint.
auto xEnd = round(x1);
auto xEnd = x1.round; // Not pure.
auto yEnd = y1 + gradient * (xEnd - x1);
auto yEnd = y1 + gradient * (xEnd - x1);
auto xGap = rfpart(x1 + 0.5);
auto xGap = rfpart(x1 + 0.5);
// This will be used in the main loop.
// This will be used in the main loop.
immutable xpxl1 = cast(int)xEnd;
immutable xpxl1 = cast(int)xEnd;
immutable ypxl1 = cast(int)floor(yEnd);
immutable ypxl1 = cast(int)yEnd.floor;
plot(xpxl1, ypxl1, rfpart(yEnd) * xGap);
plot(img, xpxl1, ypxl1, rfpart(yEnd) * xGap);
plot(xpxl1, ypxl1 + 1, fpart(yEnd) * xGap);
plot(img, xpxl1, ypxl1 + 1, fpart(yEnd) * xGap);
// First y-intersection for the main loop.
// First y-intersection for the main loop.
auto yInter = yEnd + gradient;
auto yInter = yEnd + gradient;


// Handle second endpoint.
// Handle second endpoint.
xEnd = round(x2);
xEnd = x2.round;
yEnd = y2 + gradient * (xEnd - x2);
yEnd = y2 + gradient * (xEnd - x2);
xGap = fpart(x2 + 0.5);
xGap = fpart(x2 + 0.5);
// This will be used in the main loop.
// This will be used in the main loop.
immutable xpxl2 = cast(int)xEnd;
immutable xpxl2 = cast(int)xEnd;
immutable ypxl2 = cast(int)floor(yEnd);
immutable ypxl2 = cast(int)yEnd.floor;
plot(xpxl2, ypxl2, rfpart(yEnd) * xGap);
plot(img, xpxl2, ypxl2, rfpart(yEnd) * xGap);
plot(xpxl2, ypxl2 + 1, fpart(yEnd) * xGap);
plot(img, xpxl2, ypxl2 + 1, fpart(yEnd) * xGap);


// Main loop.
// Main loop.
foreach (immutable x; xpxl1 + 1 .. xpxl2) {
foreach (immutable x; xpxl1 + 1 .. xpxl2) {
plot(x, cast(int)floor(yInter), rfpart(yInter));
plot(img, x, cast(int)yInter.floor, rfpart(yInter));
plot(x, cast(int)floor(yInter) + 1, fpart(yInter));
plot(img, x, cast(int)yInter.floor + 1, fpart(yInter));
yInter += gradient;
yInter += gradient;
}
}