all tasks
This commit is contained in:
parent
b83f433714
commit
68f8f3e56b
14735 changed files with 178959 additions and 0 deletions
1
Task/Xiaolin-Wus-line-algorithm/0DESCRIPTION
Normal file
1
Task/Xiaolin-Wus-line-algorithm/0DESCRIPTION
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implement the [[wp:Xiaolin Wu's line algorithm|Xiaolin Wu's line algorithm]] as described in Wikipedia. This algorithm draw antialiased lines. See [[Bresenham's line algorithm]] for ''aliased'' lines.
|
||||
4
Task/Xiaolin-Wus-line-algorithm/1META.yaml
Normal file
4
Task/Xiaolin-Wus-line-algorithm/1META.yaml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category:
|
||||
- Graphics algorithms
|
||||
note: Raster graphics operations
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
PROCdrawAntiAliasedLine(100, 100, 600, 400, 0, 0, 0)
|
||||
END
|
||||
|
||||
DEF PROCdrawAntiAliasedLine(x1, y1, x2, y2, r%, g%, b%)
|
||||
LOCAL dx, dy, xend, yend, grad, yf, xgap, ix1%, iy1%, ix2%, iy2%, x%
|
||||
|
||||
dx = x2 - x1
|
||||
dy = y2 - y1
|
||||
IF ABS(dx) < ABS(dy) THEN
|
||||
SWAP x1, y1
|
||||
SWAP x2, y2
|
||||
SWAP dx, dy
|
||||
ENDIF
|
||||
|
||||
IF x2 < x1 THEN
|
||||
SWAP x1, x2
|
||||
SWAP y1, y2
|
||||
ENDIF
|
||||
|
||||
grad = dy / dx
|
||||
|
||||
xend = INT(x1 + 0.5)
|
||||
yend = y1 + grad * (xend - x1)
|
||||
xgap = xend + 0.5 - x1
|
||||
ix1% = xend
|
||||
iy1% = INT(yend)
|
||||
PROCplot(ix1%, iy1%, r%, b%, g%, (INT(yend) + 1 - yend) * xgap)
|
||||
PROCplot(ix1%, iy1% + 1, r%, b%, g%, (yend - INT(yend)) * xgap)
|
||||
yf = yend + grad
|
||||
|
||||
xend = INT(x2 + 0.5)
|
||||
yend = y2 + grad * (xend - x2)
|
||||
xgap = x2 + 0.5 - xend
|
||||
ix2% = xend
|
||||
iy2% = INT(yend)
|
||||
PROCplot(ix2%, iy2%, r%, b%, g%, (INT(yend) + 1 - yend) * xgap)
|
||||
PROCplot(ix2%, iy2% + 1, r%, b%, g%, (yend - INT(yend)) * xgap)
|
||||
|
||||
FOR x% = ix1% + 1 TO ix2% - 1
|
||||
PROCplot(x%, INT(yf), r%, b%, g%, INT(yf) + 1 - yf)
|
||||
PROCplot(x%, INT(yf) + 1, r%, b%, g%, yf - INT(yf))
|
||||
yf += grad
|
||||
NEXT
|
||||
ENDPROC
|
||||
|
||||
DEF PROCplot(X%, Y%, R%, G%, B%, a)
|
||||
LOCAL C%
|
||||
C% = TINT(X%*2,Y%*2)
|
||||
COLOUR 1, R%*a + (C% AND 255)*(1-a), \
|
||||
\ G%*a + (C% >> 8 AND 255)*(1-a), \
|
||||
\ B%*a + (C% >> 16 AND 255)*(1-a)
|
||||
GCOL 1
|
||||
LINE X%*2, Y%*2, X%*2, Y%*2
|
||||
ENDPROC
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
void draw_line_antialias(
|
||||
image img,
|
||||
unsigned int x0, unsigned int y0,
|
||||
unsigned int x1, unsigned int y1,
|
||||
color_component r,
|
||||
color_component g,
|
||||
color_component b );
|
||||
103
Task/Xiaolin-Wus-line-algorithm/C/xiaolin-wus-line-algorithm-2.c
Normal file
103
Task/Xiaolin-Wus-line-algorithm/C/xiaolin-wus-line-algorithm-2.c
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
inline void _dla_changebrightness(rgb_color_p from,
|
||||
rgb_color_p to, float br)
|
||||
{
|
||||
if ( br > 1.0 ) br = 1.0;
|
||||
/* linear... Maybe something more complex could give better look */
|
||||
to->red = br * (float)from->red;
|
||||
to->green = br * (float)from->green;
|
||||
to->blue = br * (float)from->blue;
|
||||
}
|
||||
|
||||
#define plot_(X,Y,D) do{ rgb_color f_; \
|
||||
f_.red = r; f_.green = g; f_.blue = b; \
|
||||
_dla_plot(img, (X), (Y), &f_, (D)) ; }while(0)
|
||||
|
||||
inline void _dla_plot(image img, int x, int y, rgb_color_p col, float br)
|
||||
{
|
||||
rgb_color oc;
|
||||
_dla_changebrightness(col, &oc, br);
|
||||
put_pixel_clip(img, x, y, oc.red, oc.green, oc.blue);
|
||||
}
|
||||
|
||||
#define ipart_(X) ((int)(X))
|
||||
#define round_(X) ((int)(((double)(X))+0.5))
|
||||
#define fpart_(X) (((double)(X))-(double)ipart_(X))
|
||||
#define rfpart_(X) (1.0-fpart_(X))
|
||||
|
||||
#define swap_(a, b) do{ __typeof__(a) tmp; tmp = a; a = b; b = tmp; }while(0)
|
||||
void draw_line_antialias(
|
||||
image img,
|
||||
unsigned int x1, unsigned int y1,
|
||||
unsigned int x2, unsigned int y2,
|
||||
color_component r,
|
||||
color_component g,
|
||||
color_component b )
|
||||
{
|
||||
double dx = (double)x2 - (double)x1;
|
||||
double dy = (double)y2 - (double)y1;
|
||||
if ( fabs(dx) > fabs(dy) ) {
|
||||
if ( x2 < x1 ) {
|
||||
swap_(x1, x2);
|
||||
swap_(y1, y2);
|
||||
}
|
||||
double gradient = dy / dx;
|
||||
double xend = round_(x1);
|
||||
double yend = y1 + gradient*(xend - x1);
|
||||
double xgap = rfpart_(x1 + 0.5);
|
||||
int xpxl1 = xend;
|
||||
int ypxl1 = ipart_(yend);
|
||||
plot_(xpxl1, ypxl1, rfpart_(yend)*xgap);
|
||||
plot_(xpxl1, ypxl1+1, fpart_(yend)*xgap);
|
||||
double intery = yend + gradient;
|
||||
|
||||
xend = round_(x2);
|
||||
yend = y2 + gradient*(xend - x2);
|
||||
xgap = fpart_(x2+0.5);
|
||||
int xpxl2 = xend;
|
||||
int ypxl2 = ipart_(yend);
|
||||
plot_(xpxl2, ypxl2, rfpart_(yend) * xgap);
|
||||
plot_(xpxl2, ypxl2 + 1, fpart_(yend) * xgap);
|
||||
|
||||
int x;
|
||||
for(x=xpxl1+1; x <= (xpxl2-1); x++) {
|
||||
plot_(x, ipart_(intery), rfpart_(intery));
|
||||
plot_(x, ipart_(intery) + 1, fpart_(intery));
|
||||
intery += gradient;
|
||||
}
|
||||
} else {
|
||||
if ( y2 < y1 ) {
|
||||
swap_(x1, x2);
|
||||
swap_(y1, y2);
|
||||
}
|
||||
double gradient = dx / dy;
|
||||
double yend = round_(y1);
|
||||
double xend = x1 + gradient*(yend - y1);
|
||||
double ygap = rfpart_(y1 + 0.5);
|
||||
int ypxl1 = yend;
|
||||
int xpxl1 = ipart_(xend);
|
||||
plot_(xpxl1, ypxl1, rfpart_(xend)*ygap);
|
||||
plot_(xpxl1, ypxl1+1, fpart_(xend)*ygap);
|
||||
double interx = xend + gradient;
|
||||
|
||||
yend = round_(y2);
|
||||
xend = x2 + gradient*(yend - y2);
|
||||
ygap = fpart_(y2+0.5);
|
||||
int ypxl2 = yend;
|
||||
int xpxl2 = ipart_(xend);
|
||||
plot_(xpxl2, ypxl2, rfpart_(xend) * ygap);
|
||||
plot_(xpxl2, ypxl2 + 1, fpart_(xend) * ygap);
|
||||
|
||||
int y;
|
||||
for(y=ypxl1+1; y <= (ypxl2-1); y++) {
|
||||
plot_(ipart_(interx), y, rfpart_(interx));
|
||||
plot_(ipart_(interx) + 1, y, fpart_(interx));
|
||||
interx += gradient;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef swap_
|
||||
#undef plot_
|
||||
#undef ipart_
|
||||
#undef fpart_
|
||||
#undef round_
|
||||
#undef rfpart_
|
||||
103
Task/Xiaolin-Wus-line-algorithm/D/xiaolin-wus-line-algorithm.d
Normal file
103
Task/Xiaolin-Wus-line-algorithm/D/xiaolin-wus-line-algorithm.d
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import std.math, std.algorithm, grayscale_image;
|
||||
|
||||
/// Plots anti-aliased line by Xiaolin Wu's line algorithm.
|
||||
void aaLine(Color)(ref Image!Color img, double x1, double y1,
|
||||
double x2, double y2,
|
||||
in Color color)
|
||||
/*pure*/ nothrow {
|
||||
// Straight translation of Wikipedia pseudocode.
|
||||
static double round(in double x) /*pure*/ nothrow {
|
||||
return floor(x + 0.5); // Not pure.
|
||||
}
|
||||
|
||||
static double fpart(in double x) /*pure*/ nothrow {
|
||||
return x - floor(x);
|
||||
}
|
||||
|
||||
static double rfpart(in double x) /*pure*/ nothrow {
|
||||
return 1 - fpart(x);
|
||||
}
|
||||
|
||||
auto dx = x2 - x1;
|
||||
auto dy = y2 - y1;
|
||||
immutable ax = abs(dx);
|
||||
immutable ay = abs(dy);
|
||||
|
||||
static Color mixColors(in Color c1, in Color c2, in double p)
|
||||
pure nothrow {
|
||||
static if (is(Color == RGB))
|
||||
return Color(cast(ubyte)(c1.r * p + c2.r * (1 - p)),
|
||||
cast(ubyte)(c1.g * p + c2.g * (1 - p)),
|
||||
cast(ubyte)(c1.b * p + c2.b * (1 - p)));
|
||||
else
|
||||
// This doesn't work for every kind of Color.
|
||||
return Color(cast(ubyte)(c1 * p + c2 * (1 - p)));
|
||||
}
|
||||
|
||||
// Plot function set here to handle the two cases of slope.
|
||||
void delegate(in int, in int, in double) nothrow plot;
|
||||
if (ax < ay) {
|
||||
swap(x1, y1);
|
||||
swap(x2, y2);
|
||||
swap(dx, dy);
|
||||
plot = (x, y, p) {
|
||||
assert(p >= 0.0 && p <= 1.0);
|
||||
img[y, x] = mixColors(color, img[y, x], p);
|
||||
};
|
||||
} else {
|
||||
plot = (x, y, p) {
|
||||
assert(p >= 0.0 && p <= 1.0);
|
||||
img[x, y] = mixColors(color, img[x, y], p);
|
||||
};
|
||||
}
|
||||
|
||||
if (x2 < x1) {
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
}
|
||||
immutable gradient = dy / dx;
|
||||
|
||||
// Handle first endpoint.
|
||||
auto xEnd = round(x1);
|
||||
auto yEnd = y1 + gradient * (xEnd - x1);
|
||||
auto xGap = rfpart(x1 + 0.5);
|
||||
// This will be used in the main loop.
|
||||
immutable xpxl1 = cast(int)xEnd;
|
||||
immutable ypxl1 = cast(int)floor(yEnd);
|
||||
plot(xpxl1, ypxl1, rfpart(yEnd) * xGap);
|
||||
plot(xpxl1, ypxl1 + 1, fpart(yEnd) * xGap);
|
||||
// First y-intersection for the main loop.
|
||||
auto yInter = yEnd + gradient;
|
||||
|
||||
// Handle second endpoint.
|
||||
xEnd = round(x2);
|
||||
yEnd = y2 + gradient * (xEnd - x2);
|
||||
xGap = fpart(x2 + 0.5);
|
||||
// This will be used in the main loop.
|
||||
immutable xpxl2 = cast(int)xEnd;
|
||||
immutable ypxl2 = cast(int)floor(yEnd);
|
||||
plot(xpxl2, ypxl2, rfpart(yEnd) * xGap);
|
||||
plot(xpxl2, ypxl2 + 1, fpart(yEnd) * xGap);
|
||||
|
||||
// Main loop.
|
||||
foreach (immutable x; xpxl1 + 1 .. xpxl2) {
|
||||
plot(x, cast(int)floor(yInter), rfpart(yInter));
|
||||
plot(x, cast(int)floor(yInter) + 1, fpart(yInter));
|
||||
yInter += gradient;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
auto im1 = new Image!Gray(400, 300);
|
||||
im1.clear(Gray.white);
|
||||
im1.aaLine(7.4, 12.3, 307, 122.5, Gray.black);
|
||||
im1.aaLine(177.4, 12.3, 127, 222.5, Gray.black);
|
||||
im1.savePGM("xiaolin_lines1.pgm");
|
||||
|
||||
auto im2 = new Image!RGB(400, 300);
|
||||
im2.clear(RGB(0, 255, 0));
|
||||
immutable red = RGB(255, 0, 0);
|
||||
im2.aaLine(7.4, 12.3, 307, 122.5, red);
|
||||
im2.aaLine(177.4, 12.3, 127, 222.5, red);
|
||||
im2.savePPM6("xiaolin_lines2.ppm");
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package raster
|
||||
|
||||
import "math"
|
||||
|
||||
func ipart(x float64) float64 {
|
||||
return math.Floor(x)
|
||||
}
|
||||
|
||||
func round(x float64) float64 {
|
||||
return ipart(x + .5)
|
||||
}
|
||||
|
||||
func fpart(x float64) float64 {
|
||||
return x - ipart(x)
|
||||
}
|
||||
|
||||
func rfpart(x float64) float64 {
|
||||
return 1 - fpart(x)
|
||||
}
|
||||
|
||||
// AaLine plots anti-aliased line by Xiaolin Wu's line algorithm.
|
||||
func (g *Grmap) AaLine(x1, y1, x2, y2 float64) {
|
||||
// straight translation of WP pseudocode
|
||||
dx := x2 - x1
|
||||
dy := y2 - y1
|
||||
ax := dx
|
||||
if ax < 0 {
|
||||
ax = -ax
|
||||
}
|
||||
ay := dy
|
||||
if ay < 0 {
|
||||
ay = -ay
|
||||
}
|
||||
// plot function set here to handle the two cases of slope
|
||||
var plot func(int, int, float64)
|
||||
if ax < ay {
|
||||
x1, y1 = y1, x1
|
||||
x2, y2 = y2, x2
|
||||
dx, dy = dy, dx
|
||||
plot = func(x, y int, c float64) {
|
||||
g.SetPx(y, x, uint16(c*math.MaxUint16))
|
||||
}
|
||||
} else {
|
||||
plot = func(x, y int, c float64) {
|
||||
g.SetPx(x, y, uint16(c*math.MaxUint16))
|
||||
}
|
||||
}
|
||||
if x2 < x1 {
|
||||
x1, x2 = x2, x1
|
||||
y1, y2 = y2, y1
|
||||
}
|
||||
gradient := dy / dx
|
||||
|
||||
// handle first endpoint
|
||||
xend := round(x1)
|
||||
yend := y1 + gradient*(xend-x1)
|
||||
xgap := rfpart(x1 + .5)
|
||||
xpxl1 := int(xend) // this will be used in the main loop
|
||||
ypxl1 := int(ipart(yend))
|
||||
plot(xpxl1, ypxl1, rfpart(yend)*xgap)
|
||||
plot(xpxl1, ypxl1+1, fpart(yend)*xgap)
|
||||
intery := yend + gradient // first y-intersection for the main loop
|
||||
|
||||
// handle second endpoint
|
||||
xend = round(x2)
|
||||
yend = y2 + gradient*(xend-x2)
|
||||
xgap = fpart(x2 + 0.5)
|
||||
xpxl2 := int(xend) // this will be used in the main loop
|
||||
ypxl2 := int(ipart(yend))
|
||||
plot(xpxl2, ypxl2, rfpart(yend)*xgap)
|
||||
plot(xpxl2, ypxl2+1, fpart(yend)*xgap)
|
||||
|
||||
// main loop
|
||||
for x := xpxl1 + 1; x <= xpxl2-1; x++ {
|
||||
plot(x, int(ipart(intery)), rfpart(intery))
|
||||
plot(x, int(ipart(intery))+1, fpart(intery))
|
||||
intery = intery + gradient
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
// Files required to build supporting package raster are found in:
|
||||
// * This task (immediately above)
|
||||
// * Bitmap
|
||||
// * Grayscale image
|
||||
// * Write a PPM file
|
||||
|
||||
import "raster"
|
||||
|
||||
func main() {
|
||||
g := raster.NewGrmap(400, 300)
|
||||
g.AaLine(7.4, 12.3, 307, 122.5)
|
||||
g.AaLine(177.4, 12.3, 127, 222.5)
|
||||
g.Bitmap().WritePpmFile("wu.ppm")
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
load'gl2'
|
||||
coinsert'jgl2'
|
||||
|
||||
drawpt=:4 :0"0 1
|
||||
glrgb <.(-.x)*255 255 255
|
||||
glpixel y
|
||||
)
|
||||
|
||||
drawLine=:3 :0 NB. drawline x1,y1,x2,y2
|
||||
pts=. 2 2$y
|
||||
isreversed=. </ |d=. -~/pts
|
||||
r=. |.^:isreversed"1
|
||||
pts=. /:~ pts \:"1 |d
|
||||
gradient=. %~/ (\:|)d
|
||||
|
||||
'x y'=. |:pts
|
||||
xend=. <.0.5+ x
|
||||
yend=. y + gradient* xend-x
|
||||
xgap=. -.1|x+0.5
|
||||
|
||||
n=. i. >: -~/ xend
|
||||
'xlist ylist'=. (n*/~1,gradient) + ({.xend),({.yend)
|
||||
weights=. ((2&}.,~ xgap*2&{.)&.(_1&|.) (,.~-.) 1|ylist)
|
||||
weights (drawpt r)"1 2 (,:+&0 1)"1 xlist,.<.ylist
|
||||
)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
wd'pc win closeok; xywh 0 0 300 200;cc g isigraph; pas 0 0; pshow;'
|
||||
glpaint drawLine 10 10 590 390
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
NoMainWin
|
||||
WindowWidth = 270
|
||||
WindowHeight = 290
|
||||
UpperLeftX=int((DisplayWidth-WindowWidth)/2)
|
||||
UpperLeftY=int((DisplayHeight-WindowHeight)/2)
|
||||
|
||||
Global variablesInitialized : variablesInitialized = 0
|
||||
Global BackColor$ : BackColor$ = "0 0 0"
|
||||
' BackColor$ = "255 255 255"
|
||||
'now, right click randomizes BG
|
||||
Global size : size = 1'4
|
||||
global mousepoints.mouseX0, mousepoints.mouseY0, mousepoints.mouseX1, mousepoints.mouseY1
|
||||
|
||||
'StyleBits #main.gbox, 0, _WS_BORDER, 0, 0
|
||||
GraphicBox #main.gbox, 0, 0, 253, 252
|
||||
|
||||
Open "Click Twice to Form Line" For Window As #main
|
||||
Print #main, "TrapClose quit"
|
||||
Print #main.gbox, "Down; Color Black"
|
||||
Print #main.gbox, "Down; fill ";BackColor$
|
||||
Print #main.gbox, "When leftButtonUp gBoxClick"
|
||||
Print #main.gbox, "When rightButtonUp RandomBG"
|
||||
Print #main.gbox, "Size "; size
|
||||
|
||||
result = drawAntiAliasedLine(126.5, 0, 126.5, 252, "255 0 0")
|
||||
result = drawAntiAliasedLine(0, 126, 253, 126, "255 0 0")
|
||||
result = drawAntiAliasedLine(0, 0, 253, 252, "255 0 0")
|
||||
result = drawAntiAliasedLine(253, 0, 0, 252, "255 0 0")
|
||||
Wait
|
||||
|
||||
|
||||
Sub quit handle$
|
||||
Close #main
|
||||
End
|
||||
End Sub
|
||||
|
||||
sub RandomBG handle$, MouseX, MouseY
|
||||
BackColor$ = int(rnd(1)*256);" ";int(rnd(1)*256);" ";int(rnd(1)*256)
|
||||
Print #main.gbox, "CLS; fill ";BackColor$
|
||||
variablesInitialized = 0
|
||||
end sub
|
||||
|
||||
Sub gBoxClick handle$, MouseX, MouseY
|
||||
'We will use the mousepoints "struct" to hold the values
|
||||
'that way they are retained between subroutine calls
|
||||
If variablesInitialized = 0 Then
|
||||
Print #main.gbox, "CLS; fill ";BackColor$
|
||||
mousepoints.mouseX0 = MouseX
|
||||
mousepoints.mouseY0 = MouseY
|
||||
variablesInitialized = 1
|
||||
Else
|
||||
If variablesInitialized = 1 Then
|
||||
mousepoints.mouseX1 = MouseX
|
||||
mousepoints.mouseY1 = MouseY
|
||||
variablesInitialized = 0
|
||||
result = drawAntiAliasedLine(mousepoints.mouseX0, mousepoints.mouseY0, mousepoints.mouseX1, mousepoints.mouseY1, "255 0 0")
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Function Swap(Byref a,Byref b)
|
||||
aTemp = b
|
||||
b = a
|
||||
a = aTemp
|
||||
End Function
|
||||
|
||||
Function RoundtoInt(val)
|
||||
RoundtoInt = Int(val + 0.5)
|
||||
End Function
|
||||
|
||||
Function PlotAntiAliased(x, y, RGB$, b, steep)
|
||||
|
||||
RGB$ = Int(Val(Word$(BackColor$, 1))*(1-b) + Val(Word$(RGB$, 1)) * b) ; " " ; _
|
||||
Int(Val(Word$(BackColor$, 2))*(1-b) + Val(Word$(RGB$, 3)) * b) ; " " ; _
|
||||
Int(Val(Word$(BackColor$, 3))*(1-b) + Val(Word$(RGB$, 2)) * b)
|
||||
|
||||
if steep then 'x and y reversed
|
||||
Print #main.gbox, "Down; Color " + RGB$ + "; Set " + str$(y) + " " + str$(x)
|
||||
else
|
||||
Print #main.gbox, "Down; Color " + RGB$ + "; Set " + str$(x) + " " + str$(y)
|
||||
end if
|
||||
End Function
|
||||
|
||||
Function fracPart(x)
|
||||
fracPart = (x Mod 1)
|
||||
End function
|
||||
|
||||
Function invFracPart(x)
|
||||
invFracPart = (1 - fracPart(x))
|
||||
End Function
|
||||
|
||||
Function drawAntiAliasedLine(x1, y1, x2, y2, RGB$)
|
||||
If (x2 - x1)=0 Or (y2 - y1)=0 Then
|
||||
Print #main.gbox, "Down; Color " + RGB$
|
||||
result = BresenhamLine(x1, y1, x2, y2)
|
||||
Exit Function
|
||||
End If
|
||||
steep = abs(x2 - x1) < abs(y2 - y1)
|
||||
if steep then 'x and y should be reversed
|
||||
result = Swap(x1, y1)
|
||||
result = Swap(x2, y2)
|
||||
end if
|
||||
|
||||
If (x2 < x1) Then
|
||||
result = Swap(x1, x2)
|
||||
result = Swap(y1, y2)
|
||||
End If
|
||||
dx = (x2 - x1)
|
||||
dy = (y2 - y1)
|
||||
grad = (dy/ dx)
|
||||
'Handle the First EndPoint
|
||||
xend = RoundtoInt(x1)
|
||||
yend = y1 + grad * (xend - x1)
|
||||
xgap = invFracPart(x1 + 0.5)
|
||||
ix1 = xend
|
||||
iy1 = Int(yend)
|
||||
result = PlotAntiAliased(ix1, iy1, RGB$, invFracPart(yend) * xgap, steep )
|
||||
result = PlotAntiAliased(ix1, (iy1 + size), RGB$, fracPart(yend) * xgap, steep )
|
||||
yf = (yend + grad)
|
||||
'Handle the Second EndPoint
|
||||
xend = RoundtoInt(x2)
|
||||
yend = y2 + grad * (xend - x2)
|
||||
xgap = fracPart(x2 + 0.5)
|
||||
ix2 = xend
|
||||
iy2 = Int(yend)
|
||||
result = PlotAntiAliased(ix2, iy2, RGB$, invFracPart(yend) * xgap, steep )
|
||||
result = PlotAntiAliased(ix2, (iy2 + size), RGB$, fracPart(yend) * xgap, steep )
|
||||
For x = ix1 + 1 To ix2 - 1
|
||||
result = PlotAntiAliased(x, Int(yf), RGB$, invFracPart(yf), steep )
|
||||
result = PlotAntiAliased(x, (Int(yf) + size), RGB$, fracPart(yf), steep )
|
||||
yf = (yf + grad)
|
||||
Next x
|
||||
End Function
|
||||
|
||||
|
||||
Function BresenhamLine(x0, y0, x1, y1)
|
||||
dx = Abs(x1 - x0)
|
||||
dy = Abs(y1 - y0)
|
||||
sx = ((x1 > x0) + Not(x0 < x1))
|
||||
sy = ((y1 > y0) + Not(y0 < y1))
|
||||
errornum = (dx - dy)
|
||||
Do While 1
|
||||
Print #main.gbox, "Set " + str$(x0) + " " + str$(y0)
|
||||
If (x0 = x1) And (y0 = y1) Then Exit Do
|
||||
errornum2 = (2 * errornum)
|
||||
If errornum2 > (-1 * dy) Then
|
||||
errornum = (errornum - dy)
|
||||
x0 = (x0 + sx)
|
||||
End If
|
||||
If errornum2 < dx Then
|
||||
errornum = (errornum + dx)
|
||||
y0 = (y0 + sy)
|
||||
End If
|
||||
Loop
|
||||
End Function
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
sub plot(\x, \y, \c) { say "plot {x} {y} {c}" }
|
||||
|
||||
sub fpart(\x) { x - floor(x) }
|
||||
|
||||
sub draw-line(@a is copy, @b is copy) {
|
||||
my Bool \steep = abs(@b[1] - @a[1]) > abs(@b[0] - @a[0]);
|
||||
my $plot = &OUTER::plot;
|
||||
|
||||
if steep {
|
||||
$plot = -> $y, $x, $c { plot($x, $y, $c) }
|
||||
@a.=reverse;
|
||||
@b.=reverse;
|
||||
}
|
||||
if @a[0] > @b[0] { my @t = @a; @a = @b; @b = @t }
|
||||
|
||||
my (\x0,\y0) = @a;
|
||||
my (\x1,\y1) = @b;
|
||||
|
||||
my \dx = x1 - x0;
|
||||
my \dy = y1 - y0;
|
||||
my \gradient = dy / dx;
|
||||
|
||||
# handle first endpoint
|
||||
my \x-end1 = round(x0);
|
||||
my \y-end1 = y0 + gradient * (x-end1 - x0);
|
||||
my \x-gap1 = 1 - round(x0 + 0.5);
|
||||
|
||||
my \x-pxl1 = x-end1; # this will be used in the main loop
|
||||
my \y-pxl1 = floor(y-end1);
|
||||
my \c1 = fpart(y-end1) * x-gap1;
|
||||
|
||||
$plot(x-pxl1, y-pxl1 , 1 - c1) unless c1 == 1;
|
||||
$plot(x-pxl1, y-pxl1 + 1, c1 ) unless c1 == 0;
|
||||
|
||||
# handle second endpoint
|
||||
my \x-end2 = round(x1);
|
||||
my \y-end2 = y1 + gradient * (x-end2 - x1);
|
||||
my \x-gap2 = fpart(x1 + 0.5);
|
||||
|
||||
my \x-pxl2 = x-end2; # this will be used in the main loop
|
||||
my \y-pxl2 = floor(y-end2);
|
||||
my \c2 = fpart(y-end2) * x-gap2;
|
||||
|
||||
my \intery = y-end1 + gradient;
|
||||
|
||||
# main loop
|
||||
for (x-pxl1 + 1 .. x-pxl2 - 1)
|
||||
Z
|
||||
(intery, intery + gradient ... *)
|
||||
-> \x,\y {
|
||||
my \c = fpart(y);
|
||||
$plot(x, floor(y) , 1 - c) unless c == 1;
|
||||
$plot(x, floor(y) + 1, c ) unless c == 0;
|
||||
}
|
||||
|
||||
$plot(x-pxl2, y-pxl2 , 1 - c2) unless c2 == 1;
|
||||
$plot(x-pxl2, y-pxl2 + 1, c2 ) unless c2 == 0;
|
||||
}
|
||||
|
||||
draw-line [0,1], [10,2];
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
(scl 2)
|
||||
|
||||
(de plot (Img X Y C)
|
||||
(set (nth Img (*/ Y 1.0) (*/ X 1.0)) (- 100 C)) )
|
||||
|
||||
(de ipart (X)
|
||||
(* 1.0 (/ X 1.0)) )
|
||||
|
||||
(de iround (X)
|
||||
(ipart (+ X 0.5)) )
|
||||
|
||||
(de fpart (X)
|
||||
(% X 1.0) )
|
||||
|
||||
(de rfpart (X)
|
||||
(- 1.0 (fpart X)) )
|
||||
|
||||
(de xiaolin (Img X1 Y1 X2 Y2)
|
||||
(let (DX (- X2 X1) DY (- Y2 Y1))
|
||||
(use (Grad Xend Yend Xgap Xpxl1 Ypxl1 Xpxl2 Ypxl2 Intery)
|
||||
(when (> (abs DY) (abs DX))
|
||||
(xchg 'X1 'Y1 'X2 'Y2) )
|
||||
(when (> X1 X2)
|
||||
(xchg 'X1 'X2 'Y1 'Y2) )
|
||||
(setq
|
||||
Grad (*/ DY 1.0 DX)
|
||||
Xend (iround X1)
|
||||
Yend (+ Y1 (*/ Grad (- Xend X1) 1.0))
|
||||
Xgap (rfpart (+ X1 0.5))
|
||||
Xpxl1 Xend
|
||||
Ypxl1 (ipart Yend) )
|
||||
(plot Img Xpxl1 Ypxl1 (*/ (rfpart Yend) Xgap 1.0))
|
||||
(plot Img Xpxl1 (+ 1.0 Ypxl1) (*/ (fpart Yend) Xgap 1.0))
|
||||
(setq
|
||||
Intery (+ Yend Grad)
|
||||
Xend (iround X2)
|
||||
Yend (+ Y2 (*/ Grad (- Xend X2) 1.0))
|
||||
Xgap (fpart (+ X2 0.5))
|
||||
Xpxl2 Xend
|
||||
Ypxl2 (ipart Yend) )
|
||||
(plot Img Xpxl2 Ypxl2 (*/ (rfpart Yend) Xgap 1.0))
|
||||
(plot Img Xpxl2 (+ 1.0 Ypxl2) (*/ (fpart Yend) Xgap 1.0))
|
||||
(for (X (+ Xpxl1 1.0) (>= (- Xpxl2 1.0) X) (+ X 1.0))
|
||||
(plot Img X (ipart Intery) (rfpart Intery))
|
||||
(plot Img X (+ 1.0 (ipart Intery)) (fpart Intery))
|
||||
(inc 'Intery Grad) ) ) ) )
|
||||
|
||||
(let Img (make (do 90 (link (need 120 99)))) # Create image 120 x 90
|
||||
(xiaolin Img 10.0 10.0 110.0 80.0) # Draw lines
|
||||
(xiaolin Img 10.0 10.0 110.0 45.0)
|
||||
(xiaolin Img 10.0 80.0 110.0 45.0)
|
||||
(xiaolin Img 10.0 80.0 110.0 10.0)
|
||||
(out "img.pgm" # Write to bitmap file
|
||||
(prinl "P2")
|
||||
(prinl 120 " " 90)
|
||||
(prinl 100)
|
||||
(for Y Img (apply printsp Y)) ) )
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
Macro PlotB(x, y, Color, b)
|
||||
Plot(x, y, RGB(Red(Color) * (b), Green(Color) * (b), Blue(Color) * (b)))
|
||||
EndMacro
|
||||
|
||||
Procedure.f fracPart(x.f)
|
||||
ProcedureReturn x - Int(x)
|
||||
EndProcedure
|
||||
|
||||
Procedure.f invFracPart(x.f)
|
||||
ProcedureReturn 1.0 - fracPart(x)
|
||||
EndProcedure
|
||||
|
||||
Procedure drawAntiAliasedLine(x1.f, y1.f, x2.f, y2.f, color)
|
||||
Protected.f dx, dy, xend, yend, grad, yf, xgap, ix1, iy1, ix2, iy2
|
||||
Protected x
|
||||
|
||||
dx = x2 - x1
|
||||
dy = y2 - y1
|
||||
If Abs(dx) < Abs(dy)
|
||||
Swap x1, y1
|
||||
Swap x2, y2
|
||||
Swap dx, dy
|
||||
EndIf
|
||||
|
||||
If x2 < x1
|
||||
Swap x1, x2
|
||||
Swap y1, y2
|
||||
EndIf
|
||||
|
||||
grad = dy / dx
|
||||
|
||||
;handle first endpoint
|
||||
xend = Round(x1, #pb_round_nearest)
|
||||
yend = y1 + grad * (xend - x1)
|
||||
xgap = invFracPart(x1 + 0.5)
|
||||
ix1 = xend ;this will be used in the MAIN loop
|
||||
iy1 = Int(yend)
|
||||
PlotB(ix1, iy1, color, invFracPart(yend) * xgap)
|
||||
PlotB(ix1, iy1 + 1, color, fracPart(yend) * xgap)
|
||||
yf = yend + grad ;first y-intersection for the MAIN loop
|
||||
|
||||
;handle second endpoint
|
||||
xend = Round(x2, #pb_round_nearest)
|
||||
yend = y2 + grad * (xend - x2)
|
||||
xgap = fracPart(x2 + 0.5)
|
||||
ix2 = xend ;this will be used in the MAIN loop
|
||||
iy2 = Int(yend)
|
||||
PlotB(ix2, iy2, color, invFracPart(yend) * xgap)
|
||||
PlotB(ix2, iy2 + 1, color, fracPart(yend) * xgap)
|
||||
;MAIN loop
|
||||
For x = ix1 + 1 To ix2 - 1
|
||||
PlotB(x, Int(yf), color, invFracPart(yf))
|
||||
PlotB(x, Int(yf) + 1, color, fracPart(yf))
|
||||
yf + grad
|
||||
Next
|
||||
EndProcedure
|
||||
|
||||
Define w = 200, h = 200, img = 1
|
||||
CreateImage(img, w, h) ;img is internal id of the image
|
||||
|
||||
OpenWindow(0, 0, 0, w, h,"Xiaolin Wu's line algorithm", #PB_Window_SystemMenu)
|
||||
|
||||
StartDrawing(ImageOutput(img))
|
||||
drawAntiAliasedLine(80,20, 130,80, RGB(255, 0, 0))
|
||||
StopDrawing()
|
||||
|
||||
ImageGadget(0, 0, 0, w, h, ImageID(img))
|
||||
|
||||
Define event
|
||||
Repeat
|
||||
event = WaitWindowEvent()
|
||||
Until event = #PB_Event_CloseWindow
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
"""Script demonstrating drawing of anti-aliased lines using Xiaolin Wu's line
|
||||
algorithm
|
||||
|
||||
usage: python xiaolinwu.py [output-file]
|
||||
|
||||
"""
|
||||
from __future__ import division
|
||||
import sys
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def _fpart(x):
|
||||
return x - int(x)
|
||||
|
||||
def _rfpart(x):
|
||||
return 1 - _fpart(x)
|
||||
|
||||
def putpixel(img, xy, color, alpha=1):
|
||||
"""Paints color over the background at the point xy in img.
|
||||
|
||||
Use alpha for blending. alpha=1 means a completely opaque foreground.
|
||||
|
||||
"""
|
||||
c = tuple(map(lambda bg, fg: int(round(alpha * fg + (1-alpha) * bg)),
|
||||
img.getpixel(xy), color))
|
||||
img.putpixel(xy, c)
|
||||
|
||||
def draw_line(img, p1, p2, color):
|
||||
"""Draws an anti-aliased line in img from p1 to p2 with the given color."""
|
||||
x1, y1, x2, y2 = p1 + p2
|
||||
dx, dy = x2-x1, y2-y1
|
||||
steep = abs(dx) < abs(dy)
|
||||
p = lambda px, py: ((px,py), (py,px))[steep]
|
||||
|
||||
if steep:
|
||||
x1, y1, x2, y2, dx, dy = y1, x1, y2, x2, dy, dx
|
||||
if x2 < x1:
|
||||
x1, x2, y1, y2 = x2, x1, y2, y1
|
||||
|
||||
grad = dy/dx
|
||||
intery = y1 + _rfpart(x1) * grad
|
||||
def draw_endpoint(pt):
|
||||
x, y = pt
|
||||
xend = round(x)
|
||||
yend = y + grad * (xend - x)
|
||||
xgap = _rfpart(x + 0.5)
|
||||
px, py = int(xend), int(yend)
|
||||
putpixel(img, (px, py), color, _rfpart(yend) * xgap)
|
||||
putpixel(img, (px, py+1), color, _fpart(yend) * xgap)
|
||||
return px
|
||||
|
||||
xstart = draw_endpoint(p(*p1)) + 1
|
||||
xend = draw_endpoint(p(*p2))
|
||||
|
||||
for x in range(xstart, xend):
|
||||
y = int(intery)
|
||||
putpixel(img, p(x, y), color, _rfpart(intery))
|
||||
putpixel(img, p(x, y+1), color, _fpart(intery))
|
||||
intery += grad
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 2:
|
||||
print 'usage: python xiaolinwu.py [output-file]'
|
||||
sys.exit(-1)
|
||||
|
||||
blue = (0, 0, 255)
|
||||
yellow = (255, 255, 0)
|
||||
img = Image.new("RGB", (500,500), blue)
|
||||
for a in range(10, 431, 60):
|
||||
draw_line(img, (10, 10), (490, a), yellow)
|
||||
draw_line(img, (10, 10), (a, 490), yellow)
|
||||
draw_line(img, (10, 10), (490, 490), yellow)
|
||||
filename = sys.argv[1]
|
||||
img.save(filename)
|
||||
print 'image saved to', filename
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*REXX program plots/draws a line using the Xiaolin Wu line algorithm.*/
|
||||
background = 'fa'x /*background char: middle-dot. */
|
||||
image. = background /*fill the array with middle-dots*/
|
||||
plotC = '░▒▓█' /*chars used for plotting points.*/
|
||||
EoE = 1000 /*EOE = End Of Earth, er... plot.*/
|
||||
do j=-EoE to +EoE /*draw grid from lowest──►highest*/
|
||||
image.j.0 = '─' /*draw the horizontal axis. */
|
||||
image.0.j = '│' /* " " verical " */
|
||||
end /*j*/
|
||||
image.0.0 = '┼' /*"draw" the axis origin (char). */
|
||||
parse arg xi yi xf yf . /*allow specifying line-end pts. */
|
||||
if xi=='' | xi==',' then xi = 1 /*if not specified, use default. */
|
||||
if yi=='' | yi==',' then yi = 2 /* " " " " " */
|
||||
if xf=='' | xf==',' then xf = 11 /* " " " " " */
|
||||
if yf=='' | yf==',' then yf = 12 /* " " " " " */
|
||||
minX=0; minY=0 /*used as limits for plotting. */
|
||||
maxX=0; maxY=0 /* " " " " " */
|
||||
call line_draw xi, yi, xf, yf /*call subroutine and draw line. */
|
||||
border = 2 /*allow additional space for plot*/
|
||||
minX=minX-border*2; maxX=maxX+border*2
|
||||
minY=minY-border ; maxY=maxY+border
|
||||
do y=maxY by -1 to minY; _= /*build a row*/
|
||||
do x=minX to maxX
|
||||
_=_ || image.x.y
|
||||
end /*x*/
|
||||
say _ /*display row*/
|
||||
end /*y*/
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*────────────────────────────────DRAW_LINE subroutine──────────────────*/
|
||||
line_draw: procedure expose background image. minX maxX minY maxY plotC
|
||||
parse arg x1, y1, x2, y2; switchXY=0; dx=x2-x1
|
||||
dy=y2-y1
|
||||
if abs(dx)<abs(dy) then do
|
||||
parse value x1 y1 with y1 x1 /*swap x1 & y1*/
|
||||
parse value x2 y2 with y2 x2 /*swap x2 & y2*/
|
||||
parse value dx dy with dy dx /*swap dx & dy*/
|
||||
end
|
||||
if x2<x1 then do
|
||||
parse value x1 x2 with x2 x1 /*swap x1 & x2*/
|
||||
parse value y1 y2 with y2 y1 /*swap y1 & y2*/
|
||||
switchXY=1
|
||||
end
|
||||
|
||||
gradient = dy/dx
|
||||
xend = round(x1) /*────1st endpoint────────────────────*/
|
||||
yend = y1 + gradient * (xend-x1)
|
||||
intery = yend + gradient
|
||||
xgap = 1 - fpart(x1+.5)
|
||||
xpx11 = xend; ypx11 = floor(yend); ypx11_=ypx11+1
|
||||
call plotXY xpx11, ypx11, brite(1-fpart(yend*xgap)),switchXY
|
||||
call plotXY xpx11, ypx11_, brite( fpart(yend*xgap)),switchXY
|
||||
|
||||
xend = round(x2) /*────2nd endpoint────────────────────*/
|
||||
yend = y2 + gradient * (xend-x2)
|
||||
xgap = fpart(x2+.5)
|
||||
xpx12 = xend; ypx12 = floor(yend); ypx12_=ypx12+1
|
||||
call plotXY xpx12, ypx12, brite(1-fpart(yend*xgap)), switchXY
|
||||
call plotXY xpx12, ypx12_, brite( fpart(yend*xgap)), switchXY
|
||||
|
||||
do x=xpx11+1 to xpx12-1 /*────draw the line───────────────────*/
|
||||
!intery = floor(intery)
|
||||
!intery_ = !intery+1
|
||||
call plotXY x, !intery, brite(1-fpart(intery)), switchXY
|
||||
call plotXY x, !intery_, brite( fpart(intery)), switchXY
|
||||
intery = intery + gradient
|
||||
end /*x*/
|
||||
return
|
||||
/*────────────────────────────────BRITE subroutine──────────────────────*/
|
||||
brite: procedure expose background plotC; parse arg p
|
||||
return substr(background || plotC, 1+round(abs(p)*length(plotC)), 1)
|
||||
/*────────────────────────────────PLOTXY subroutine─────────────────────*/
|
||||
plotXY: procedure expose image. minX maxX minY maxY
|
||||
parse arg xx, yy, bc, switchYX; if switchYX then parse arg yy, xx
|
||||
image.xx.yy=bc; minX=min(minX,xx); maxX=max(maxX,xx)
|
||||
minY=min(minY,yy); maxY=max(maxY,yy)
|
||||
return
|
||||
/*────────────────────────────────FLOOR subroutine──────────────────────*/
|
||||
floor: procedure; parse arg ?; _=trunc(?); return _-(?<0)*(?\=_)
|
||||
/*────────────────────────────────FPART subroutine──────────────────────*/
|
||||
fpart: procedure; parse arg ?; return abs(?-trunc(?))
|
||||
/*────────────────────────────────ROUND subroutine─────────arg2 is place*/
|
||||
round: return format(arg(1), , word(arg(2) 0, 1))
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
def ipart(n); n.truncate; end
|
||||
def fpart(n); n - ipart(n); end
|
||||
def rfpart(n); 1.0 - fpart(n); end
|
||||
|
||||
class Pixmap
|
||||
def draw_line_antialised(p1, p2, colour)
|
||||
x1, y1 = p1.x, p1.y
|
||||
x2, y2 = p2.x, p2.y
|
||||
|
||||
steep = (y2 - y1).abs > (x2 - x1).abs
|
||||
if steep
|
||||
x1, y1 = y1, x1
|
||||
x2, y2 = y2, x2
|
||||
end
|
||||
if x1 > x2
|
||||
x1, x2 = x2, x1
|
||||
y1, y2 = y2, y1
|
||||
end
|
||||
deltax = x2 - x1
|
||||
deltay = (y2 - y1).abs
|
||||
gradient = 1.0 * deltay / deltax
|
||||
|
||||
# handle the first endpoint
|
||||
xend = x1.round
|
||||
yend = y1 + gradient * (xend - x1)
|
||||
xgap = rfpart(x1 + 0.5)
|
||||
xpxl1 = xend
|
||||
ypxl1 = ipart(yend)
|
||||
put_colour(xpxl1, ypxl1, colour, steep, rfpart(yend)*xgap)
|
||||
put_colour(xpxl1, ypxl1 + 1, colour, steep, fpart(yend)*xgap)
|
||||
itery = yend + gradient
|
||||
|
||||
# handle the second endpoint
|
||||
xend = x2.round
|
||||
yend = y2 + gradient * (xend - x2)
|
||||
xgap = rfpart(x2 + 0.5)
|
||||
xpxl2 = xend
|
||||
ypxl2 = ipart(yend)
|
||||
put_colour(xpxl2, ypxl2, colour, steep, rfpart(yend)*xgap)
|
||||
put_colour(xpxl2, ypxl2 + 1, colour, steep, fpart(yend)*xgap)
|
||||
|
||||
# in between
|
||||
(xpxl1 + 1).upto(xpxl2 - 1).each do |x|
|
||||
put_colour(x, ipart(itery), colour, steep, rfpart(itery))
|
||||
put_colour(x, ipart(itery) + 1, colour, steep, fpart(itery))
|
||||
itery = itery + gradient
|
||||
end
|
||||
end
|
||||
|
||||
def put_colour(x, y, colour, steep, c)
|
||||
x, y = y, x if steep
|
||||
self[x, y] = anti_alias(colour, self[x, y], c)
|
||||
end
|
||||
|
||||
def anti_alias(new, old, ratio)
|
||||
blended = new.values.zip(old.values).map {|n, o| (n*ratio + o*(1.0 - ratio)).round}
|
||||
RGBColour.new(*blended)
|
||||
end
|
||||
end
|
||||
|
||||
bitmap = Pixmap.new(500, 500)
|
||||
bitmap.fill(RGBColour::BLUE)
|
||||
10.step(430, 60) do |a|
|
||||
bitmap.draw_line_antialised(Pixel[10, 10], Pixel[490,a], RGBColour::YELLOW)
|
||||
bitmap.draw_line_antialised(Pixel[10, 10], Pixel[a,490], RGBColour::YELLOW)
|
||||
end
|
||||
bitmap.draw_line_antialised(Pixel[10, 10], Pixel[490,490], RGBColour::YELLOW)
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package require Tcl 8.5
|
||||
package require Tk
|
||||
|
||||
proc ::tcl::mathfunc::ipart x {expr {int($x)}}
|
||||
proc ::tcl::mathfunc::fpart x {expr {$x - int($x)}}
|
||||
proc ::tcl::mathfunc::rfpart x {expr {1.0 - fpart($x)}}
|
||||
|
||||
proc drawAntialiasedLine {image colour p1 p2} {
|
||||
lassign $p1 x1 y1
|
||||
lassign $p2 x2 y2
|
||||
|
||||
set steep [expr {abs($y2 - $y1) > abs($x2 - $x1)}]
|
||||
if {$steep} {
|
||||
lassign [list $x1 $y1] y1 x1
|
||||
lassign [list $x2 $y2] y2 x2
|
||||
}
|
||||
if {$x1 > $x2} {
|
||||
lassign [list $x1 $x2] x2 x1
|
||||
lassign [list $y1 $y2] y2 y1
|
||||
}
|
||||
set deltax [expr {$x2 - $x1}]
|
||||
set deltay [expr {abs($y2 - $y1)}]
|
||||
set gradient [expr {1.0 * $deltay / $deltax}]
|
||||
|
||||
# handle the first endpoint
|
||||
set xend [expr {round($x1)}]
|
||||
set yend [expr {$y1 + $gradient * ($xend - $x1)}]
|
||||
set xgap [expr {rfpart($x1 + 0.5)}]
|
||||
set xpxl1 $xend
|
||||
set ypxl1 [expr {ipart($yend)}]
|
||||
plot $image $colour $steep $xpxl1 $ypxl1 [expr {rfpart($yend)*$xgap}]
|
||||
plot $image $colour $steep $xpxl1 [expr {$ypxl1+1}] [expr {fpart($yend)*$xgap}]
|
||||
set itery [expr {$yend + $gradient}]
|
||||
|
||||
# handle the second endpoint
|
||||
set xend [expr {round($x2)}]
|
||||
set yend [expr {$y2 + $gradient * ($xend - $x2)}]
|
||||
set xgap [expr {rfpart($x2 + 0.5)}]
|
||||
set xpxl2 $xend
|
||||
set ypxl2 [expr {ipart($yend)}]
|
||||
plot $image $colour $steep $xpxl2 $ypxl2 [expr {rfpart($yend)*$xgap}]
|
||||
plot $image $colour $steep $xpxl2 [expr {$ypxl2+1}] [expr {fpart($yend)*$xgap}]
|
||||
|
||||
for {set x [expr {$xpxl1 + 1}]} {$x < $xpxl2} {incr x} {
|
||||
plot $image $colour $steep $x [expr {ipart($itery)}] [expr {rfpart($itery)}]
|
||||
plot $image $colour $steep $x [expr {ipart($itery) + 1}] [expr {fpart($itery)}]
|
||||
set itery [expr {$itery + $gradient}]
|
||||
}
|
||||
}
|
||||
|
||||
proc plot {image colour steep x y c} {
|
||||
set point [expr {$steep ? [list $y $x] : [list $x $y]}]
|
||||
set newColour [antialias $colour [getPixel $image $point] $c]
|
||||
setPixel $image $newColour $point
|
||||
}
|
||||
|
||||
proc antialias {newColour oldColour c} {
|
||||
# get the new colour r,g,b
|
||||
if {[scan $newColour "#%2x%2x%2x%c" nr ng gb -] != 3} {
|
||||
scan [colour2rgb $newColour] "#%2x%2x%2x" nr ng nb
|
||||
}
|
||||
|
||||
# get the current colour r,g,b
|
||||
scan $oldColour "#%2x%2x%2x" cr cg cb
|
||||
|
||||
# blend the colours in the ratio defined by "c"
|
||||
foreach new [list $nr $ng $nb] curr [list $cr $cg $cb] {
|
||||
append blend [format {%02x} [expr {round($new*$c + $curr*(1.0-$c))}]]
|
||||
}
|
||||
return #$blend
|
||||
}
|
||||
|
||||
proc colour2rgb {color_name} {
|
||||
foreach part [winfo rgb . $color_name] {
|
||||
append colour [format %02x [expr {$part >> 8}]]
|
||||
}
|
||||
return #$colour
|
||||
}
|
||||
|
||||
set img [newImage 500 500]
|
||||
fill $img blue
|
||||
for {set a 10} {$a < 500} {incr a 60} {
|
||||
drawAntialiasedLine $img yellow {10 10} [list 490 $a]
|
||||
drawAntialiasedLine $img yellow {10 10} [list $a 490]
|
||||
}
|
||||
toplevel .wu
|
||||
label .wu.l -image $img
|
||||
pack .wu.l
|
||||
Loading…
Add table
Add a link
Reference in a new issue