Xiaolin Wu's line algorithm: Difference between revisions

Content added Content deleted
No edit summary
(Updated D entry)
Line 184: Line 184:
double x1, double y1,
double x1, double y1,
double x2, double y2,
double x2, double y2,
in Color color) /*pure*/ nothrow @safe {
in Color color) pure nothrow @safe @nogc {
// Straight translation of Wikipedia pseudocode.
// Straight translation of Wikipedia pseudocode.

static double round(in double x) pure nothrow {
// std.math.round is not pure. **
static double round(in double x) pure nothrow @safe @nogc {
return floor(x + 0.5);
return floor(x + 0.5);
}
}


static double fpart(in double x) pure nothrow @safe {
static double fpart(in double x) pure nothrow @safe @nogc {
return x - x.floor;
return x - x.floor;
}
}


static double rfpart(in double x) pure nothrow @safe {
static double rfpart(in double x) pure nothrow @safe @nogc {
return 1 - fpart(x);
return 1 - fpart(x);
}
}
Line 215: Line 217:


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


Line 222: Line 224:
swap(x2, y2);
swap(x2, y2);
swap(dx, dy);
swap(dx, dy);
//plot = (img, x, y, p) {
//plot = (img, x, y, p, col) {
plot = (ref Image!Color img, x, y, p) {
plot = (ref img, x, y, p, col) {
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(col, img[y, x], p);
};
};
} else {
} else {
//plot = (img, x, y, p) {
//plot = (img, x, y, p, col) {
plot = (ref Image!Color img, x, y, p) {
plot = (ref img, x, y, p, col) {
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(col, img[x, y], p);
};
};
}
}
Line 242: Line 244:


// Handle first endpoint.
// Handle first endpoint.
auto xEnd = x1.round; // Not pure.
auto xEnd = round(x1);
auto yEnd = y1 + gradient * (xEnd - x1);
auto yEnd = y1 + gradient * (xEnd - x1);
auto xGap = rfpart(x1 + 0.5);
auto xGap = rfpart(x1 + 0.5);
Line 248: Line 250:
immutable xpxl1 = cast(int)xEnd;
immutable xpxl1 = cast(int)xEnd;
immutable ypxl1 = cast(int)yEnd.floor;
immutable ypxl1 = cast(int)yEnd.floor;
plot(img, xpxl1, ypxl1, rfpart(yEnd) * xGap);
plot(img, xpxl1, ypxl1, rfpart(yEnd) * xGap, color);
plot(img, xpxl1, ypxl1 + 1, fpart(yEnd) * xGap);
plot(img, xpxl1, ypxl1 + 1, fpart(yEnd) * xGap, color);
// 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 = x2.round;
xEnd = round(x2);
yEnd = y2 + gradient * (xEnd - x2);
yEnd = y2 + gradient * (xEnd - x2);
xGap = fpart(x2 + 0.5);
xGap = fpart(x2 + 0.5);
Line 260: Line 262:
immutable xpxl2 = cast(int)xEnd;
immutable xpxl2 = cast(int)xEnd;
immutable ypxl2 = cast(int)yEnd.floor;
immutable ypxl2 = cast(int)yEnd.floor;
plot(img, xpxl2, ypxl2, rfpart(yEnd) * xGap);
plot(img, xpxl2, ypxl2, rfpart(yEnd) * xGap, color);
plot(img, xpxl2, ypxl2 + 1, fpart(yEnd) * xGap);
plot(img, xpxl2, ypxl2 + 1, fpart(yEnd) * xGap, color);


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