Xiaolin Wu's line algorithm: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(36 intermediate revisions by 7 users not shown)
Line 12:
*   See   [[Bresenham's line algorithm]]   for ''aliased'' lines.
<br><br>
 
=={{header|Action!}}==
{{libheader|Action! Tool Kit}}
{{libheader|Action! Real Math}}
<syntaxhighlight lang="action!">INCLUDE "H6:REALMATH.ACT"
 
REAL one
 
PROC PutBigPixel(INT x,y,col)
IF x>=0 AND x<=79 AND y>=0 AND y<=47 THEN
y==LSH 2
IF col<0 THEN col=0
ELSEIF col>15 THEN col=15 FI
Color=col
Plot(x,y)
DrawTo(x,y+3)
FI
RETURN
 
INT FUNC Abs(INT x)
IF x<0 THEN RETURN (-x) FI
RETURN (x)
 
PROC Swap(INT POINTER a,b)
INT tmp
 
tmp=a^ a^=b^ b^=tmp
RETURN
 
PROC Line(INT x1,y1,x2,y2,col)
INT x,y,dx,dy,c
INT POINTER px,py
REAL rx,ry,grad,rcol,tmp1,tmp2
 
dx=Abs(x2-x1)
dy=Abs(y2-y1)
IF dy>dx THEN
Swap(@x1,@y1)
Swap(@x2,@y2)
px=@y py=@x
ELSE
px=@x py=@y
FI
 
IF x1>x2 THEN
Swap(@x1,@x2)
Swap(@y1,@y2)
FI
 
x=x2-x1
IF x=0 THEN x=1 FI
IntToRealForNeg(x,rx)
IntToRealForNeg(y2-y1,ry)
RealDiv(ry,rx,grad)
IntToRealForNeg(y1,ry)
IntToReal(col,rcol)
FOR x=x1 TO x2
DO
Frac(ry,tmp1)
IF IsNegative(tmp1) THEN
RealAdd(one,tmp1,tmp2)
RealAssign(tmp2,tmp1)
FI
RealMult(rcol,tmp1,tmp2)
c=Round(tmp2)
y=Floor(ry)
PutBigPixel(px^,py^,col-c)
y==+1
PutBigPixel(px^,py^,c)
RealAdd(ry,grad,tmp1)
RealAssign(tmp1,ry)
OD
RETURN
 
PROC Main()
BYTE CH=$02FC ;Internal hardware value for last key pressed
REAL tmp,c
BYTE i,x1,y1,x2,y2
 
MathInit()
IntToReal(1,one)
 
Graphics(9)
FOR i=0 TO 11
DO
Line(0,i*4,38,1+i*5,15)
Line(40+i*4,0,41+i*6,47,15)
OD
 
DO UNTIL CH#$FF OD
CH=$FF
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Xiaolin_Wu's_line_algorithm.png Screenshot from Atari 8-bit computer]
 
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
 
/* ARM assembly Raspberry PI */
Line 661 ⟶ 756:
FBVARSCinfo_fin:
 
</syntaxhighlight>
</lang>
 
=={{header|ATS}}==
{{trans|ObjectIcon}}
 
The following program writes (to standard output) a Portable Grayscale Map without gamma correction. One can use Netpbm to do the gamma correction. Thus, for example:
<pre>
$ patscc -g -O2 -std=gnu2x -DATS_MEMALLOC_GCBDW xiaolin_wu_line_algorithm.dats -lgc -lm
$ ./a.out | pnmgamma -lineartobt709 | pnmtopng > image.png
</pre>
 
For mathematics, I simply make foreign language calls to C. There is some mathematics support in <code>libats/libc</code>, and [[ats2-xprelude]] provides even more. However, making the foreign language calls is trivial, as you can see below.
 
<syntaxhighlight lang="ats">
#include "share/atspre_staload.hats"
staload UN = "prelude/SATS/unsafe.sats"
 
%{^
#include <float.h>
#include <math.h>
%}
 
typedef color = double
 
typedef drawing_surface (u0 : int, v0 : int,
u1 : int, v1 : int) =
[u0 <= u1; v0 <= v1]
'{
u0 = int u0,
v0 = int v0,
u1 = int u1,
v1 = int v1,
pixels = matrixref (color, (u1 - u0) + 1, (v1 - v0) + 1)
}
 
fn
drawing_surface_make
{u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(u0 : int u0,
v0 : int v0,
u1 : int u1,
v1 : int v1)
: drawing_surface (u0, v0, u1, v1) =
let
val w = succ (u1 - u0) and h = succ (v1 - v0)
in
'{
u0 = u0,
v0 = v0,
u1 = u1,
v1 = v1,
pixels = matrixref_make_elt (i2sz w, i2sz h, 0.0)
}
end
 
fn
drawing_surface_get_at
{u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(s : drawing_surface (u0, v0, u1, v1),
x : int,
y : int)
: color =
let
val '{ u0 = u0, v0 = v0, u1 = u1, v1 = v1, pixels = pixels } = s
and x = g1ofg0 x and y = g1ofg0 y
in
if (u0 <= x) * (x <= u1) * (v0 <= y) * (y <= v1) then
(* Notice there are THREE values in the square brackets. The
matrixref does not store its dimensions and so we have to
specify a stride as the second value. The value must,
however, be the CORRECT stride. This is checked at compile
time. (Here ATS is striving to be efficient rather than
convenient!) *)
pixels[x - u0, succ (v1 - v0), v1 - y]
else
$extval (double, "nan (\"0\")")
end
 
fn
drawing_surface_set_at
{u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(s : drawing_surface (u0, v0, u1, v1),
x : int,
y : int,
c : color)
: void =
let
val '{ u0 = u0, v0 = v0, u1 = u1, v1 = v1, pixels = pixels } = s
and x = g1ofg0 x and y = g1ofg0 y
in
if (u0 <= x) * (x <= u1) * (v0 <= y) * (y <= v1) then
pixels[x - u0, succ (v1 - v0), v1 - y] := c
end
 
(* Indices outside the drawing_surface are allowed. They are handled
by treating them as if you were trying to draw on the air. *)
overload [] with drawing_surface_get_at
overload [] with drawing_surface_set_at
 
fn
write_PGM {u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(outf : FILEref,
s : drawing_surface (u0, v0, u1, v1))
: void =
(* Write a Portable Grayscale Map. *)
let
val '{ u0 = u0, v0 = v0, u1 = u1, v1 = v1, pixels = pixels } = s
 
stadef w = (u1 - u0) + 1
stadef h = (v1 - v0) + 1
val w : int w = succ (u1 - u0)
and h : int h = succ (v1 - v0)
 
fun
loop {x, y : int | 0 <= x; x <= w; 0 <= y; y <= h}
.<h - y, w - x>.
(x : int x,
y : int y) : void =
if y = h then
()
else if x = w then
loop (0, succ y)
else
let
(* I do no gamma correction, but gamma correction can be
done afterwards by running the output through "pnmgamma
-lineartobt709" *)
val intensity = 1.0 - pixels[x, h, y]
val pgm_value : int =
g0f2i ($extfcall (double, "rint", 65535 * intensity))
val more_significant_byte = pgm_value / 256
and less_significant_byte = pgm_value mod 256
val msbyte = int2uchar0 more_significant_byte
and lsbyte = int2uchar0 less_significant_byte
in
fprint_val<uchar> (outf, msbyte);
fprint_val<uchar> (outf, lsbyte);
loop (succ x, y)
end
in
fprintln! (outf, "P5");
fprintln! (outf, w, " ", h);
fprintln! (outf, "65535");
loop (0, 0)
end
 
fn
ipart (x : double) : int =
g0f2i ($extfcall (double, "floor", x))
 
fn
iround (x : double) : int =
ipart (x + 0.5)
 
fn
fpart (x : double) : double =
x - $extfcall (double, "floor", x)
 
fn
rfpart (x : double) : double =
1.0 - fpart (x)
 
fn
plot {u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(s : drawing_surface (u0, v0, u1, v1),
x : int,
y : int,
c : color)
: void =
let
(* One might prefer a more sophisticated function than mere
addition. *)
val combined_color = s[x, y] + c
in
s[x, y] := min (combined_color, 1.0)
end
 
fn
_drawln {u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(s : drawing_surface (u0, v0, u1, v1),
x0 : double,
y0 : double,
x1 : double,
y1 : double,
steep : bool)
: void =
let
val dx = x1 - x0 and dy = y1 - y0
val gradient = (if dx = 0.0 then 1.0 else dy / dx) : double
 
(* Handle the first endpoint. *)
val xend = iround x0
val yend = y0 + (gradient * (g0i2f xend - x0))
val xgap = rfpart (x0 + 0.5)
val xpxl1 = xend and ypxl1 = ipart yend
val () =
if steep then
begin
plot (s, ypxl1, xpxl1, rfpart yend * xgap);
plot (s, succ ypxl1, xpxl1, fpart yend * xgap)
end
else
begin
plot (s, xpxl1, ypxl1, rfpart yend * xgap);
plot (s, xpxl1, succ ypxl1, fpart yend * xgap)
end
 
(* The first y-intersection. Notice it is a "var" (a variable)
instead of a "val" (an immutable value). There is no need to
box it as a "ref", the way one must typically do in an ML
dialect. We could have done so, but the following treats the
variable as an ordinary C automatic variable, and is more
efficient. *)
var intery : double = yend + gradient
 
(* Handle the second endpoint. *)
val xend = iround (x1)
val yend = y1 + (gradient * (g0i2f xend - x1))
val xgap = fpart (x1 + 0.5)
val xpxl2 = xend and ypxl2 = ipart yend
val () =
if steep then
begin
plot (s, ypxl2, xpxl2, rfpart yend * xgap);
plot (s, succ ypxl2, xpxl2, fpart yend * xgap)
end
else
begin
plot (s, xpxl2, ypxl2, rfpart yend * xgap);
plot (s, xpxl2, succ ypxl2, fpart yend * xgap)
end
in
(* Loop over the rest of the points. I use procedural "for"-loops
instead of the more usual (for ATS) tail recursion. *)
if steep then
let
var x : int
in
for (x := succ xpxl1; x <> xpxl2; x := succ x)
begin
plot (s, ipart intery, x, rfpart intery);
plot (s, succ (ipart intery), x, fpart intery);
intery := intery + gradient
end
end
else
let
var x : int
in
for (x := succ xpxl1; x <> xpxl2; x := succ x)
begin
plot (s, x, ipart intery, rfpart intery);
plot (s, x, succ (ipart intery), fpart intery);
intery := intery + gradient
end
end
end
 
fn
draw_line {u0, v0, u1, v1 : int | u0 <= u1; v0 <= v1}
(s : drawing_surface (u0, v0, u1, v1),
x0 : double,
y0 : double,
x1 : double,
y1 : double)
: void =
let
val xdiff = abs (x1 - x0) and ydiff = abs (y1 - y0)
in
if ydiff <= xdiff then
begin
if x0 <= x1 then
_drawln (s, x0, y0, x1, y1, false)
else
_drawln (s, x1, y1, x0, y0, false)
end
else
begin
if y0 <= y1 then
_drawln (s, y0, x0, y1, x1, true)
else
_drawln (s, y1, x1, y0, x0, true)
end
end
 
implement
main0 () =
let
macdef M_PI = $extval (double, "M_PI")
 
val u0 = 0 and v0 = 0
and u1 = 639 and v1 = 479
 
val s = drawing_surface_make (u0, v0, u1, v1)
 
fun
loop (theta : double) : void =
if theta < 360.0 then
let
val cos_theta = $extfcall (double, "cos",
theta * (M_PI / 180.0))
and sin_theta = $extfcall (double, "sin",
theta * (M_PI / 180.0))
and x0 = 380.0 and y0 = 130.0
val x1 = x0 + (cos_theta * 1000.0)
and y1 = y0 + (sin_theta * 1000.0)
in
draw_line (s, x0, y0, x1, y1);
loop (theta + 5.0)
end
in
loop 0.0;
write_PGM (stdout_ref, s)
end
</syntaxhighlight>
 
{{out}}
The following image has been gamma-corrected with pnmgamma (although the thumbnail image may look strange).
[[File:Xiaolin wu line algorithm ATS.2023.04.27.14.16.28.png|thumb|none|alt=A starburst of straight lines, black on white.]]
 
=={{header|AutoHotkey}}==
{{libheader|GDIP}}
<langsyntaxhighlight AutoHotkeylang="autohotkey">#SingleInstance, Force
#NoEnv
SetBatchLines, -1
Line 769 ⟶ 1,182:
DllCall("msvcrt\_i64to" U, "Int64",n, "Str",S, "Int",Base)
return, S
}</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> PROCdrawAntiAliasedLine(100, 100, 600, 400, 0, 0, 0)
END
Line 826 ⟶ 1,239:
GCOL 1
LINE X%*2, Y%*2, X%*2, Y%*2
ENDPROC</langsyntaxhighlight>
 
=={{header|C fast fixed-point}}==
 
This is an implementation in C using fixed-point to speed things up significantly.
Suitable for 32-bit+ architectures.
For reference and comparison, the floating-point version is also included.
 
This implementation of plot() only draws white on a fixed canvas, but can easily be modified.
 
<syntaxhighlight lang="c">// Something to draw on
static uint8_t canvas[240][240];
 
// Paint pixel white
static void inline plot(int16_t x, int16_t y, uint16_t alpha) {
canvas[y][x] = 255 - (((255 - canvas[y][x]) * (alpha & 0x1FF)) >> 8);
}
 
// Xiaolin Wu's line algorithm
// Coordinates are Q16 fixed point, ie 0x10000 == 1
void wuline(int32_t x0, int32_t y0, int32_t x1, int32_t y1) {
bool steep = ((y1 > y0) ? (y1 - y0) : (y0 - y1)) > ((x1 > x0) ? (x1 - x0) : (x0 - x1));
 
if(steep) { int32_t z = x0; x0 = y0; y0 = z; z = x1; x1 = y1; y1 = z; }
if(x0 > x1) { int32_t z = x0; x0 = x1; x1 = z; z = y0; y0 = y1; y1 = z; }
 
int32_t dx = x1 - x0, dy = y1 - y0;
int32_t gradient = ((dx >> 8) == 0) ? 0x10000 : (dy << 8) / (dx >> 8);
 
// handle first endpoint
int32_t xend = (x0 + 0x8000) & 0xFFFF0000;
int32_t yend = y0 + ((gradient * (xend - x0)) >> 16);
int32_t xgap = 0x10000 - ((x0 + 0x8000) & 0xFFFF);
int16_t xpxl1 = xend >> 16; // this will be used in the main loop
int16_t ypxl1 = yend >> 16;
if(steep) {
plot(ypxl1, xpxl1, 0x100 - (((0x100 - ((yend >> 8) & 0xFF)) * xgap) >> 16));
plot(ypxl1 + 1, xpxl1, 0x100 - (( ((yend >> 8) & 0xFF) * xgap) >> 16));
} else {
plot(xpxl1, ypxl1, 0x100 - (((0x100 - ((yend >> 8) & 0xFF)) * xgap) >> 16));
plot(xpxl1, ypxl1 + 1, 0x100 - (( ((yend >> 8) & 0xFF) * xgap) >> 16));
}
int32_t intery = yend + gradient; // first y-intersection for the main loop
 
// handle second endpoint
xend = (x1 + 0x8000) & 0xFFFF0000;
yend = y1 + ((gradient * (xend - x1)) >> 16);
xgap = (x1 + 0x8000) & 0xFFFF;
int16_t xpxl2 = xend >> 16; //this will be used in the main loop
int16_t ypxl2 = yend >> 16;
if(steep) {
plot(ypxl2, xpxl2, 0x100 - (((0x100 - ((yend >> 8) & 0xFF)) * xgap) >> 16));
plot(ypxl2 + 1, xpxl2, 0x100 - (( ((yend >> 8) & 0xFF) * xgap) >> 16));
} else {
plot(xpxl2, ypxl2, 0x100 - (((0x100 - ((yend >> 8) & 0xFF)) * xgap) >> 16));
plot(xpxl2, ypxl2 + 1, 0x100 - (( ((yend >> 8) & 0xFF) * xgap) >> 16));
}
 
// main loop
if(steep) {
for(int32_t x = xpxl1 + 1; x < xpxl2; x++) {
plot((intery >> 16) , x, (intery >> 8) & 0xFF );
plot((intery >> 16) + 1, x, 0x100 - ((intery >> 8) & 0xFF));
intery += gradient;
}
} else {
for(int32_t x = xpxl1 + 1; x < xpxl2; x++) {
plot(x, (intery >> 16), (intery >> 8) & 0xFF );
plot(x, (intery >> 16) + 1, 0x100 - ((intery >> 8) & 0xFF));
intery += gradient;
}
}
}
 
// Paint pixel white (floating point version, for reference only)
static void inline plotf(int16_t x, int16_t y, float alpha) {
canvas[y][x] = 255 - ((255 - canvas[y][x]) * (1.0 - alpha));
}
 
// Xiaolin Wu's line algorithm (floating point version, for reference only)
void wulinef(float x0, float y0, float x1, float y1) {
bool steep = fabs(y1 - y0) > fabs(x1 - x0);
 
if(steep) { float z = x0; x0 = y0; y0 = z; z = x1; x1 = y1; y1 = z; }
if(x0 > x1) { float z = x0; x0 = x1; x1 = z; z = y0; y0 = y1; y1 = z; }
 
float dx = x1 - x0, dy = y1 - y0;
float gradient = (dx == 0.0) ? 1.0 : dy / dx;
 
// handle first endpoint
uint16_t xend = round(x0);
float yend = y0 + gradient * ((float)xend - x0);
float xgap = 1.0 - (x0 + 0.5 - floor(x0 + 0.5));
int16_t xpxl1 = xend; // this will be used in the main loop
int16_t ypxl1 = floor(yend);
if(steep) {
plotf(ypxl1, xpxl1, (1.0 - (yend - floor(yend))) * xgap);
plotf(ypxl1 + 1.0, xpxl1, (yend - floor(yend)) * xgap);
} else {
plotf(xpxl1, ypxl1, (1.0 - (yend - floor(yend))) * xgap);
plotf(xpxl1, ypxl1 + 1.0, (yend - floor(yend)) * xgap);
}
float intery = yend + gradient; // first y-intersection for the main loop
 
// handle second endpoint
xend = round(x1);
yend = y1 + gradient * ((float)xend - x1);
xgap = x1 + 0.5 - floor(x1 + 0.5);
int16_t xpxl2 = xend; //this will be used in the main loop
int16_t ypxl2 = floor(yend);
if(steep) {
plotf(ypxl2, xpxl2, (1.0 - (yend - floor(yend))) * xgap);
plotf(ypxl2 + 1.0, xpxl2, (yend - floor(yend)) * xgap);
} else {
plotf(xpxl2, ypxl2, (1.0 - (yend - floor(yend))) * xgap);
plotf(xpxl2, ypxl2 + 1.0, (yend - floor(yend)) * xgap);
}
 
// main loop
if(steep) {
for(uint16_t x = xpxl1 + 1; x < xpxl2; x++) {
plotf(floor(intery), x, (1.0 - (intery - floor(intery))));
plotf(floor(intery) + 1, x, (intery - floor(intery) ));
intery += gradient;
}
} else {
for(uint16_t x = xpxl1 + 1; x < xpxl2; x++) {
plotf(x, floor(intery), (1.0 - (intery - floor(intery))));
plotf(x, floor(intery) + 1, (intery - floor(intery) ));
intery += gradient;
}
}
}
 
void wudemo() {
 
// Clear the canvas
memset(canvas, 0, sizeof(canvas));
 
// Of course it doesn't make sense to use slow floating point trig. functions here
// This is just for demo purposes
static float wudemo_v;
wudemo_v += 0.005;
float x = sinf(wudemo_v) * 50;
float y = cosf(wudemo_v) * 50;
 
// Draw using fast fixed-point version
wuline ((x + 125) * (1 << 16), (y + 125) * (1 << 16), (-x + 125) * (1 << 16), (-y + 125) * (1 << 16));
 
// Draw using reference version for comparison
wulinef( x + 115, y + 115, -x + 115, -y + 115 );
 
// -- insert display code here --
showme(canvas);
 
}
</syntaxhighlight>
 
=={{header|C}}==
Line 832 ⟶ 1,401:
This implementation follows straightforwardly the pseudocode given on Wikipedia. (Further analysis of the code could give suggestions for improvements).
 
<langsyntaxhighlight lang="c">void draw_line_antialias(
image img,
unsigned int x0, unsigned int y0,
Line 838 ⟶ 1,407:
color_component r,
color_component g,
color_component b );</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">inline void _dla_changebrightness(rgb_color_p from,
rgb_color_p to, float br)
{
Line 943 ⟶ 1,512:
#undef round_
#undef rfpart_
</syntaxhighlight>
</lang>
 
=={{header|C++}}==
 
<langsyntaxhighlight lang="c++">
#include <functional>
#include <algorithm>
Line 1,021 ⟶ 1,590:
}
}
</syntaxhighlight>
</lang>
 
=={{header|C#}}==
<syntaxhighlight lang="c">
<lang c>
public class Line
{
Line 1,133 ⟶ 1,702:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Common Lisp}}==
{{trans|Scheme}}
 
The program outputs a transparency mask in Portable Gray Map format. It draws lines normal to a tractrix. They trace out a catenary.
 
<syntaxhighlight lang="lisp">
;;; The program outputs a transparency mask in plain Portable Gray Map
;;; format.
;;; -------------------------------------------------------------------
 
(defstruct (drawing-surface
(:constructor make-drawing-surface (u0 v0 u1 v1)))
(u0 0 :type fixnum :read-only t)
(v0 0 :type fixnum :read-only t)
(u1 0 :type fixnum :read-only t)
(v1 0 :type fixnum :read-only t)
(pixels (make-array (* (- u1 u0 -1) (- v1 v0 -1))
:element-type 'single-float
:initial-element 0.0)))
 
;;; In calls to drawing-surface-ref and drawing-surface-set, indices
;;; outside the drawing_surface are allowed. Such indices are treated
;;; as if you were trying to draw on the air.
 
(defun drawing-surface-ref (s x y)
(let ((u0 (drawing-surface-u0 s))
(v0 (drawing-surface-v0 s))
(u1 (drawing-surface-u1 s))
(v1 (drawing-surface-v1 s)))
(if (and (<= u0 x) (<= x u1) (<= v0 y) (<= y v1))
(aref (drawing-surface-pixels s)
(+ (- x u0) (* (- v1 y) (- u1 u0 -1))))
0.0))) ;; The Scheme for this returns +nan.0
 
(defun drawing-surface-set (s x y opacity)
(let ((u0 (drawing-surface-u0 s))
(v0 (drawing-surface-v0 s))
(u1 (drawing-surface-u1 s))
(v1 (drawing-surface-v1 s)))
(when (and (<= u0 x) (<= x u1) (<= v0 y) (<= y v1))
(setf (aref (drawing-surface-pixels s)
(+ (- x u0) (* (- v1 y) (- u1 u0 -1))))
opacity))))
 
(defun write-transparency-mask (s)
;; In the Scheme, I had the program write a Portable Arbitrary Map
;; with both a color and a transparency map. Here, by contrast, only
;; the transparency map will be output. It will be in plain Portable
;; Gray Map format, but representing opacities rather than
;; whitenesses. (Thus there will be no need for gamma corrections.)
;; See the pgm(5) manpage for a discussion of this use of PGM
;; format.
(let* ((u0 (drawing-surface-u0 s))
(v0 (drawing-surface-v0 s))
(u1 (drawing-surface-u1 s))
(v1 (drawing-surface-v1 s))
(w (- u1 u0 -1))
(h (- v1 v0 -1))
(|(w * h) - 1| (1- (* w h)))
(opacities (drawing-surface-pixels s)))
;; "format" is not standard in Scheme, although it is widely
;; implemented as an extension. However, in Common Lisp it is
;; standardized. So let us use it.
(format t "P2~%")
(format t "# transparency map~%")
(format t "~a ~a~%" w h)
(format t "255~%")
(loop for i from 0 to |(w * h) - 1|
do (let* ((opacity (aref opacities i))
(byteval (round (* 255 opacity))))
;; Using "plain" PGM format avoids the issue of how to
;; write raw bytes. OTOH it makes the output file large
;; and slow to work with. (In the R7RS Scheme,
;; "bytevectors" provided an obvious way to write
;; bytes.)
(princ byteval)
(terpri)))))
 
;;;-------------------------------------------------------------------
 
(defun ipart (x) (floor x))
(defun iround (x) (ipart (+ x 0.5)))
(defun fpart (x) (nth-value 1 (floor x)))
(defun rfpart (x) (- 1.0 (fpart x)))
 
(defun plot-shallow (s x y opacity)
(let ((combined-opacity
(+ opacity (drawing-surface-ref s x y))))
(drawing-surface-set s x y (min combined-opacity 1.0))))
 
(defun plot-steep (s x y opacity)
(plot-shallow s y x opacity))
 
(defun drawln% (s x0 y0 x1 y1 plot)
(let* ((dx (- x1 x0))
(dy (- y1 y0))
(gradient (if (zerop dx) 1.0 (/ dy dx)))
 
;; Handle the first endpoint.
(xend (iround x0))
(yend (+ y0 (* gradient (- xend x0))))
(xgap (rfpart (+ x0 0.5)))
(xpxl1 xend)
(ypxl1 (ipart yend))
(_ (funcall plot s xpxl1 ypxl1 (* (rfpart yend) xgap)))
(_ (funcall plot s xpxl1 (1+ ypxl1) (* (fpart yend) xgap)))
 
(first-y-intersection (+ yend gradient))
 
;; Handle the second endpoint.
(xend (iround x1))
(yend (+ y1 (* gradient (- xend x1))))
(xgap (fpart (+ x1 0.5)))
(xpxl2 xend)
(ypxl2 (ipart yend))
(_ (funcall plot s xpxl2 ypxl2 (* (rfpart yend) xgap)))
(_ (funcall plot s xpxl2 (1+ ypxl2) (* (fpart yend) xgap))))
 
;; Loop over the rest of the points.
(do ((x (+ xpxl1 1) (1+ x))
(intery first-y-intersection (+ intery gradient)))
((= x xpxl2))
(funcall plot s x (ipart intery) (rfpart intery))
(funcall plot s x (1+ (ipart intery)) (fpart intery)))))
 
(defun draw-line (s x0 y0 x1 y1)
(let ((x0 (coerce x0 'single-float))
(y0 (coerce y0 'single-float))
(x1 (coerce x1 'single-float))
(y1 (coerce y1 'single-float)))
(let ((xdiff (abs (- x1 x0)))
(ydiff (abs (- y1 y0))))
(if (<= ydiff xdiff)
(if (<= x0 x1)
(drawln% s x0 y0 x1 y1 #'plot-shallow)
(drawln% s x1 y1 x0 y0 #'plot-shallow))
(if (<= y0 y1)
(drawln% s y0 x0 y1 x1 #'plot-steep)
(drawln% s y1 x1 y0 x0 #'plot-steep))))))
 
;;;-------------------------------------------------------------------
;;; Draw a catenary as the evolute of a tractrix. See
;;; https://en.wikipedia.org/w/index.php?title=Tractrix&oldid=1143719802#Properties
;;; See also https://archive.is/YfgXW
 
(defvar u0 -399)
(defvar v0 -199)
(defvar u1 400)
(defvar v1 600)
 
(defvar s (make-drawing-surface u0 v0 u1 v1))
 
 
(loop for i from -300 to 300 by 10
for t_ = (/ i 100.0) ; Independent parameter.
for x = (- t_ (tanh t_)) ; Parametric tractrix coordinates.
for y = (/ (cosh t_)) ;
for u = y ; Parametric normal vector.
for v = (* y (sinh t_)) ;
for x0 = (* 100.0 (- x (* 10.0 u))) ; Scaled for plotting.
for y0 = (* 100.0 (- y (* 10.0 v)))
for x1 = (* 100.0 (+ x (* 10.0 u)))
for y1 = (* 100.0 (+ y (* 10.0 v)))
do (draw-line s x0 y0 x1 y1))
 
(write-transparency-mask s)
 
;;;-------------------------------------------------------------------
</syntaxhighlight>
 
Here is a script to run the program and produce a PNG image.
<syntaxhighlight lang="sh">
#!/bin/sh
 
sbcl --script xiaolin_wu_line_algorithm.lisp > alpha.pgm
pamgradient black black darkblue darkblue 800 800 > bluegradient.pam
pamgradient red red magenta magenta 800 800 > redgradient.pam
pamcomp -alpha=alpha.pgm redgradient.pam bluegradient.pam | pamtopng > image.png
</syntaxhighlight>
 
{{out}}
[[File:Xiaolin wu line algorithm CommonLisp.png|thumb|none|alt=A catenary as the evolute of a tractrix. Reddish gradient on bluish gradient.]]
 
=={{header|D}}==
{{trans|Go}}
This performs the mixing of the colors, both in grey scale and RGB.
<langsyntaxhighlight lang="d">import std.math, std.algorithm, grayscale_image;
 
/// Plots anti-aliased line by Xiaolin Wu's line algorithm.
Line 1,246 ⟶ 1,998:
im2.aaLine(177.4, 12.3, 127, 222.5, red);
im2.savePPM6("xiaolin_lines2.ppm");
}</langsyntaxhighlight>
 
=={{header|Fortran}}==
{{trans|Common Lisp}}
 
The program outputs a Portable Gray Map representing a transparency mask. The mask is full of straight lines, drawn by a solution of this Rosetta Code task. Some of the lines draw a piecewise approximation of an ellipse, and others draw the normals of the ellipse. The normals form an envelope that is the evolute of the ellipse.
 
<syntaxhighlight lang="fortran">
program xiaolin_wu_line_algorithm
use, intrinsic :: ieee_arithmetic
implicit none
 
type :: drawing_surface
integer :: u0, v0, u1, v1
real, allocatable :: pixels(:)
end type drawing_surface
 
interface
subroutine point_plotter (s, x, y, opacity)
import drawing_surface
type(drawing_surface), intent(inout) :: s
integer, intent(in) :: x, y
real, intent(in) :: opacity
end subroutine point_plotter
end interface
 
real, parameter :: pi = 4.0 * atan (1.0)
 
integer, parameter :: u0 = -499
integer, parameter :: v0 = -374
integer, parameter :: u1 = 500
integer, parameter :: v1 = 375
 
real, parameter :: a = 200.0 ! Ellipse radius on x axis.
real, parameter :: b = 350.0 ! Ellipse radius on y axis.
 
type(drawing_surface) :: s
integer :: i, step_size
real :: t, c, d
real :: x, y
real :: xnext, ynext
real :: u, v
real :: rhs, ad, bc
real :: x0, y0, x1, y1
 
s = make_drawing_surface (u0, v0, u1, v1)
 
! Draw both an ellipse and the normals of that ellipse.
step_size = 2
do i = 0, 359, step_size
! Parametric representation of an ellipse.
t = i * (pi / 180.0)
c = cos (t)
d = sin (t)
x = a * c
y = b * d
 
! Draw a piecewise linear approximation of the ellipse. The
! endpoints of the line segments will lie on the curve.
xnext = a * cos ((i + step_size) * (pi / 180.0))
ynext = b * sin ((i + step_size) * (pi / 180.0))
call draw_line (s, x, y, xnext, ynext)
 
! The parametric equation of the normal:
!
! (a * sin (t) * xnormal) - (b * cos (t) * ynormal)
! = (a**2 - b**2) * cos (t) * sin (t)
!
! That is:
!
! (a * d * xnormal) - (b * c * ynormal) = (a**2 - b**2) * c * d
!
rhs = (a**2 - b**2) * c * d
ad = a * d
bc = b * c
if (abs (ad) < abs (bc)) then
x0 = -1000.0
y0 = ((ad * x0) - rhs) / bc
x1 = 1000.0
y1 = ((ad * x1) - rhs) / bc
else
y0 = -1000.0
x0 = (rhs - (bc * y0)) / ad
y1 = 1000.0
x1 = (rhs - (bc * y1)) / ad
end if
 
call draw_line (s, x0, y0, x1, y1)
end do
 
call write_transparency_mask (s)
 
contains
 
function make_drawing_surface (u0, v0, u1, v1) result (s)
integer, intent(in) :: u0, v0, u1, v1
type(drawing_surface) :: s
 
integer :: w, h
 
if (u1 < u0 .or. v1 < v0) error stop
s%u0 = u0; s%v0 = v0
s%u1 = u1; s%v1 = v1
w = u1 - u0 + 1
h = v1 - v0 + 1
allocate (s%pixels(0:(w * h) - 1), source = 0.0)
end function make_drawing_surface
 
function drawing_surface_ref (s, x, y) result (c)
type(drawing_surface), intent(in) :: s
integer, intent(in) :: x, y
real :: c
 
! In calls to drawing_surface_ref and drawing_surface_set, indices
! outside the drawing_surface are allowed. Such indices are
! treated as if you were trying to draw on the air.
if (s%u0 <= x .and. x <= s%u1 .and. s%v0 <= y .and. y <= s%v1) then
c = s%pixels((x - s%u0) + ((s%v1 - y) * (s%u1 - s%u0 + 1)))
else
c = ieee_value (s%pixels(0), ieee_quiet_nan)
end if
end function drawing_surface_ref
 
subroutine drawing_surface_set (s, x, y, c)
type(drawing_surface), intent(inout) :: s
integer, intent(in) :: x, y
real, intent(in) :: c
 
! In calls to drawing_surface_ref and drawing_surface_set, indices
! outside the drawing_surface are allowed. Such indices are
! treated as if you were trying to draw on the air.
 
if (s%u0 <= x .and. x <= s%u1 .and. s%v0 <= y .and. y <= s%v1) then
s%pixels((x - s%u0) + ((s%v1 - y) * (s%u1 - s%u0 + 1))) = c
end if
end subroutine drawing_surface_set
 
subroutine write_transparency_mask (s)
type(drawing_surface), intent(in) :: s
 
! Write a transparency mask, in plain (ASCII or EBCDIC) Portable
! Gray Map format, but representing opacities rather than
! whitenesses. (Thus there will be no need for gamma corrections.)
! See the pgm(5) manpage for a discussion of this use of PGM
! format.
 
integer :: w, h
integer :: i
 
w = s%u1 - s%u0 + 1
h = s%v1 - s%v0 + 1
 
write (*, '("P2")')
write (*, '("# transparency mask")')
write (*, '(I0, 1X, I0)') w, h
write (*, '("255")')
write (*, '(15I4)') (nint (255 * s%pixels(i)), i = 0, (w * h) - 1)
end subroutine write_transparency_mask
 
subroutine draw_line (s, x0, y0, x1, y1)
type(drawing_surface), intent(inout) :: s
real, intent(in) :: x0, y0, x1, y1
 
real :: xdiff, ydiff
 
xdiff = abs (x1 - x0)
ydiff = abs (y1 - y0)
if (ydiff <= xdiff) then
if (x0 <= x1) then
call drawln (s, x0, y0, x1, y1, plot_shallow)
else
call drawln (s, x1, y1, x0, y0, plot_shallow)
end if
else
if (y0 <= y1) then
call drawln (s, y0, x0, y1, x1, plot_steep)
else
call drawln (s, y1, x1, y0, x0, plot_steep)
end if
end if
end subroutine draw_line
 
subroutine drawln (s, x0, y0, x1, y1, plot)
type(drawing_surface), intent(inout) :: s
real, intent(in) :: x0, y0, x1, y1
procedure(point_plotter) :: plot
 
real :: dx, dy, gradient
real :: yend, xgap
real :: first_y_intersection, intery
integer :: xend
integer :: xpxl1, ypxl1
integer :: xpxl2, ypxl2
integer :: x
 
dx = x1 - x0; dy = y1 - y0
if (dx == 0.0) then
gradient = 1.0
else
gradient = dy / dx
end if
 
! Handle the first endpoint.
xend = iround (x0)
yend = y0 + (gradient * (xend - x0))
xgap = rfpart (x0 + 0.5)
xpxl1 = xend
ypxl1 = ipart (yend)
call plot (s, xpxl1, ypxl1, rfpart (yend) * xgap)
call plot (s, xpxl1, ypxl1 + 1, fpart (yend) * xgap)
 
first_y_intersection = yend + gradient
 
! Handle the second endpoint.
xend = iround (x1)
yend = y1 + (gradient * (xend - x1))
xgap = fpart (x1 + 0.5)
xpxl2 = xend
ypxl2 = ipart (yend)
call plot (s, xpxl2, ypxl2, (rfpart (yend) * xgap))
call plot (s, xpxl2, ypxl2 + 1, fpart (yend) * xgap)
 
! Loop over the rest of the points.
intery = first_y_intersection
do x = xpxl1 + 1, xpxl2 - 1
call plot (s, x, ipart (intery), rfpart (intery))
call plot (s, x, ipart (intery) + 1, fpart (intery))
intery = intery + gradient
end do
end subroutine drawln
 
subroutine plot_shallow (s, x, y, opacity)
type(drawing_surface), intent(inout) :: s
integer, intent(in) :: x, y
real, intent(in) :: opacity
 
real :: combined_opacity
 
! Let us simply add opacities, up to the maximum of 1.0. You might
! wish to do something different, of course.
combined_opacity = opacity + drawing_surface_ref (s, x, y)
call drawing_surface_set (s, x, y, min (combined_opacity, 1.0))
end subroutine plot_shallow
 
subroutine plot_steep (s, x, y, opacity)
type(drawing_surface), intent(inout) :: s
integer, intent(in) :: x, y
real, intent(in) :: opacity
call plot_shallow (s, y, x, opacity)
end subroutine plot_steep
 
elemental function ipart (x) result (i)
real, intent(in) :: x
integer :: i
i = floor (x)
end function ipart
 
elemental function iround (x) result (i)
real, intent(in) :: x
integer :: i
i = ipart (x + 0.5)
end function iround
 
elemental function fpart (x) result (y)
real, intent(in) :: x
real :: y
y = modulo (x, 1.0)
end function fpart
 
elemental function rfpart (x) result (y)
real, intent(in) :: x
real :: y
y = 1.0 - fpart (x)
end function rfpart
 
end program xiaolin_wu_line_algorithm
</syntaxhighlight>
 
Here is a shell script that runs the program and creates a PNG. The background of the image is one pattern, and the foreground is another. The foreground, however, is masked by the transparency mask, and so only all those straight lines we drew show up in the PNG.
 
<syntaxhighlight lang="shell">
#!/bin/sh
 
# Using the optimizer, even at low settings, avoids trampolines and
# executable stacks.
gfortran -std=f2018 -g -O1 xiaolin_wu_line_algorithm.f90
 
./a.out > alpha.pgm
ppmpat -anticamo -randomseed=36 1000 750 | pambrighten -value=-60 -saturation=50 > fg.pam
ppmpat -poles -randomseed=57 1000 750 | pambrighten -value=+200 -saturation=-80 > bg.pam
pamcomp -alpha=alpha.pgm fg.pam bg.pam | pamtopng > image.png
</syntaxhighlight>
 
{{out}}
[[File:Xiaolin wu line algorithm Fortran.png|thumb|none|alt=An ellipse and its normals (forming an evolute as their envelope), all of it in goofy colors.]]
 
=={{header|FreeBASIC}}==
Line 1,252 ⟶ 2,299:
Only changed xend=round() in xend=ipart() to make it more in line with FreeBASIC's own line drawing routine. Rfpart give me some trouble so I changed if somewhat.
The small functions where all converted into macro's
<langsyntaxhighlight FreeBASIClang="freebasic">' version 21-06-2015
' compile with: fbc -s console or fbc -s gui
' Xiaolin Wu’s line-drawing algorithm
Line 1,378 ⟶ 2,425:
While Inkey <> "" : Wend
Sleep
End</langsyntaxhighlight>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package raster
 
import "math"
Line 1,459 ⟶ 2,506:
intery = intery + gradient
}
}</langsyntaxhighlight>
Demonstration program:
<langsyntaxhighlight lang="go">package main
 
// Files required to build supporting package raster are found in:
Line 1,476 ⟶ 2,523:
g.AaLine(177.4, 12.3, 127, 222.5)
g.Bitmap().WritePpmFile("wu.ppm")
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
Line 1,482 ⟶ 2,529:
Example makes use of [http://hackage.haskell.org/package/JuicyPixels <tt>JuicyPixels</tt>] for serialization to PNG format and and [http://hackage.haskell.org/package/primitive <tt>primitive</tt>] to abstract away memory-related operations. This is a fairly close translation of the algorithm as described on [https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm Wikipedia]:
 
<langsyntaxhighlight lang="haskell">{-# LANGUAGE ScopedTypeVariables #-}
 
module Main (main) where
Line 1,592 ⟶ 2,639:
 
-- Write it out to a file on disc
writePng "xiaolin-wu-algorithm.png" img</langsyntaxhighlight>
 
Building and running this program will generate an output PNG file named <code>xiaolin-wu-algorithm.png</code> showing a white antialiased diagonal line.
 
=={{header|Icon}}==
{{trans|ObjectIcon}}
 
Please be aware that the program below is written for classical "University of Arizona" Icon, and not for Unicon or Object Icon. It uses a graphics system designed for machines of past times.
 
I have taken the Object Icon program and made the minimum number of changes needed to get it running as an Arizona Icon program. As with the Object Icon, a window comes up and then you can draw lines on it by pressing the left mouse button. Pressing "q" or "Q" will quit the program. Instead of a PNG, the program writes a GIF. Instead of varying the opacity of a line's pixels, the program varies the shade of gray.
 
<syntaxhighlight lang="icon">
link graphics
 
$define YES 1
$define NO &null
 
procedure main ()
local width, height
local done, w, event
local x1, y1, x2, y2, press_is_active
 
width := 640
height := 480
 
w := WOpen ("size=" || width || "," || height, "bg=white") |
stop ("failed to open a window")
 
press_is_active := NO
done := NO
while /done do
{
if *(Pending (w)) ~= 0 then
{
event := Event (w)
case event of
{
QuitEvents () : done := YES
&lpress :
{
if /press_is_active then
{
x1 := &x; y1 := &y
press_is_active := YES
}
else
{
x2 := &x; y2 := &y
draw_line (w, x1, y1, x2, y2)
press_is_active := NO
}
}
}
}
}
 
# GIF is the only format "regular" Icon is documented to be able to
# write on all platforms. (Icon used to run on, for instance, 16-bit
# MSDOS boxes.)
WriteImage (w, "xiaolin_wu_line_algorithm_Arizona.gif") |
stop ("failed to write a GIF")
end
 
procedure draw_line (w, x0, y0, x1, y1)
local steep
local dx, dy, gradient
local xend, yend, xgap, intery
local xpxl1, ypxl1
local xpxl2, ypxl2
local x
 
x0 := real (x0)
y0 := real (y0)
x1 := real (x1)
y1 := real (y1)
 
# In Icon, comparisons DO NOT return boolean values! They either
# SUCCEED or they FAIL. Thus the need for an "if-then-else" here.
steep := (if abs (y1 - y0) > abs (x1 - x0) then YES else NO)
 
if \steep then { x0 :=: y0; x1 :=: y1 }
if x0 > x1 then { x0 :=: x1; y0 :=: y1 }
dx := x1 - x0; dy := y1 - y0
gradient := (if dx = 0 then 1.0 else dy / dx)
 
# Handle the first endpoint.
xend := round (x0); yend := y0 + (gradient * (xend - x0))
xgap := rfpart (x0 + 0.5)
xpxl1 := xend; ypxl1 := ipart (yend)
if \steep then
{
plot (w, ypxl1, xpxl1, rfpart (yend) * xgap)
plot (w, ypxl1 + 1, xpxl1, fpart(yend) * xgap)
}
else
{
plot (w, xpxl1, ypxl1, rfpart (yend) * xgap)
plot (w, xpxl1, ypxl1 + 1, fpart (yend) * xgap)
}
 
# The first y-intersection.
intery := yend + gradient
 
# Handle the second endpoint.
xend := round (x1); yend := y1 + (gradient * (xend - x1))
xgap := fpart (x1 + 0.5)
xpxl2 := xend; ypxl2 := ipart (yend)
if \steep then
{
plot (w, ypxl2, xpxl2, rfpart (yend) * xgap)
plot (w, ypxl2 + 1, xpxl2, fpart (yend) * xgap)
}
else
{
plot (w, xpxl2, ypxl2, rfpart (yend) * xgap)
plot (w, xpxl2, ypxl2 + 1, fpart (yend) * xgap)
}
 
if \steep then
every x := xpxl1 + 1 to xpxl2 - 1 do
{
plot (w, ipart (intery), x, rfpart (intery))
plot (w, ipart (intery) + 1, x, fpart (intery))
intery := intery + gradient
}
else
every x := xpxl1 + 1 to xpxl2 - 1 do
{
plot(w, x, ipart (intery), rfpart (intery))
plot(w, x, ipart (intery) + 1, fpart (intery))
intery := intery + gradient
}
 
return
end
 
procedure plot (w, x, y, c)
# In Object Icon, one can vary the opacity. But not in "regular"
# Icon. Here we vary, instead, the shade of gray.
c := round ((1.0 - c) * 65535)
Fg (w, c || "," || c || "," || c)
DrawPoint (w, x, y)
return
end
 
procedure ipart (x)
local i
i := integer (x)
return (if i = x then i else if x < 0 then i - 1 else i)
end
 
procedure round (x)
return ipart (x + 0.5)
end
 
procedure fpart (x)
return x - ipart (x)
end
 
procedure rfpart (x)
return 1.0 - fpart (x)
end
 
# Unlike Object Icon, "regular" Icon has no "abs" built-in.
procedure abs (x)
return (if x < 0 then -x else x)
end
</syntaxhighlight>
 
{{out}}
An example GIF:
[[File:Xiaolin wu line algorithm Arizona.2023.04.27.09.17.33.gif|thumb|none|alt=A GIF of the window drawn by a run of the Icon program. An assortment of anti-aliased straight lines in black on white.]]
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">load'gl2'
coinsert'jgl2'
 
Line 1,622 ⟶ 2,838:
weights=. ((2&}.,~ xgap*2&{.)&.(_1&|.) (,.~-.) 1|ylist)
weights (drawpt r)"1 2 (,:+&0 1)"1 xlist,.<.ylist
)</langsyntaxhighlight>
 
'''Example use:'''
<langsyntaxhighlight lang="j"> wd'pc win closeok; xywh 0 0 300 200;cc g isigraph; pas 0 0; pshow;' NB. J6 or earlier
wd'pc win closeok; minwh 600 400;cc g isidraw flush; pshow;' NB. J802 or later
glpaint glclear ''
glpaint drawLine 10 10 590 390</langsyntaxhighlight>
 
=={{header|Java}}==
[[File:xiaolinwu_java.png|200px|thumb|right]]
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import java.awt.*;
import static java.lang.Math.*;
import javax.swing.*;
Line 1,741 ⟶ 2,957:
});
}
}</langsyntaxhighlight>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<langsyntaxhighlight lang="julia">using Images
 
fpart(x) = mod(x, one(x))
Line 1,820 ⟶ 3,036:
 
img = fill(Gray(1.0N0f8), 250, 250);
drawline!(img, 8, 8, 192, 154)</langsyntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">// version 1.1.2
 
import java.awt.*
Line 1,924 ⟶ 3,140:
f.isVisible = true
}
}</langsyntaxhighlight>
 
=={{header|Liberty BASIC}}==
<syntaxhighlight lang="lb">
<lang lb>
NoMainWin
WindowWidth = 270
Line 2,083 ⟶ 3,299:
Loop
End Function
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">ClearAll[ReverseFractionalPart, ReplacePixelWithAlpha, DrawEndPoint, DrawLine]
ReverseFractionalPart[x_] := 1 - FractionalPart[x]
ReplacePixelWithAlpha[img_Image, pos_ -> colvals : {_, _, _},
Line 2,135 ⟶ 3,351:
]
image = ConstantImage[Black, {100, 100}];
Fold[DrawLine[#1, {20, 10}, #2] &, image, AngleVector[{20, 10}, {75, #}] & /@ Subdivide[0, Pi/2, 10]]</langsyntaxhighlight>
 
=={{header|MATLAB}}==
{{trans|Julia}}
<syntaxhighlight lang="MATLAB}}">
clear all;close all;clc;
% Example usage:
img = ones(250, 250);
img = drawline(img, 8, 8, 192, 154);
imshow(img); % Display the image
 
function img = drawline(img, x0, y0, x1, y1)
function f = fpart(x)
f = mod(x, 1);
end
 
function rf = rfpart(x)
rf = 1 - fpart(x);
end
 
steep = abs(y1 - y0) > abs(x1 - x0);
 
if steep
[x0, y0] = deal(y0, x0);
[x1, y1] = deal(y1, x1);
end
if x0 > x1
[x0, x1] = deal(x1, x0);
[y0, y1] = deal(y1, y0);
end
 
dx = x1 - x0;
dy = y1 - y0;
grad = dy / dx;
 
if dx == 0
grad = 1.0;
end
 
% handle first endpoint
xend = round(x0);
yend = y0 + grad * (xend - x0);
xgap = rfpart(x0 + 0.5);
xpxl1 = xend;
ypxl1 = floor(yend);
 
if steep
img(ypxl1, xpxl1) = rfpart(yend) * xgap;
img(ypxl1+1, xpxl1) = fpart(yend) * xgap;
else
img(xpxl1, ypxl1 ) = rfpart(yend) * xgap;
img(xpxl1, ypxl1+1) = fpart(yend) * xgap;
end
intery = yend + grad; % first y-intersection for the main loop
 
% handle second endpoint
xend = round(x1);
yend = y1 + grad * (xend - x1);
xgap = fpart(x1 + 0.5);
xpxl2 = xend;
ypxl2 = floor(yend);
if steep
img(ypxl2, xpxl2) = rfpart(yend) * xgap;
img(ypxl2+1, xpxl2) = fpart(yend) * xgap;
else
img(xpxl2, ypxl2 ) = rfpart(yend) * xgap;
img(xpxl2, ypxl2+1) = fpart(yend) * xgap;
end
 
% main loop
if steep
for x = (xpxl1+1):(xpxl2-1)
img(floor(intery), x) = rfpart(intery);
img(floor(intery)+1, x) = fpart(intery);
intery = intery + grad;
end
else
for x = (xpxl1+1):(xpxl2-1)
img(x, floor(intery) ) = rfpart(intery);
img(x, floor(intery)+1) = fpart(intery);
intery = intery + grad;
end
end
end
</syntaxhighlight>
 
 
=={{header|Modula-2}}==
{{trans|Fortran}}
 
The program outputs a transparency map in Portable Gray Map format. It draws lines normal to a parabola. The envelope formed is a semicubic parabola.
 
<syntaxhighlight lang="Modula2">
MODULE Xiaolin_Wu_Task;
 
(* The program is for ISO Modula-2. To compile with GNU Modula-2
(gm2), use the "-fiso" option. *)
 
IMPORT RealMath;
IMPORT SRawIO;
IMPORT STextIO;
IMPORT SWholeIO;
IMPORT SYSTEM;
 
CONST MaxDrawingSurfaceIndex = 1999;
CONST MaxDrawingSurfaceSize =
(MaxDrawingSurfaceIndex + 1) * (MaxDrawingSurfaceIndex + 1);
 
TYPE DrawingSurfaceIndex = [0 .. MaxDrawingSurfaceIndex];
TYPE PixelsIndex = [0 .. MaxDrawingSurfaceSize - 1];
TYPE DrawingSurface =
RECORD
u0, v0, u1, v1 : INTEGER;
pixels : ARRAY PixelsIndex OF REAL;
END;
TYPE PointPlotter = PROCEDURE (VAR DrawingSurface,
INTEGER, INTEGER, REAL);
 
PROCEDURE InitializeDrawingSurface (VAR s : DrawingSurface;
u0, v0, u1, v1 : INTEGER);
VAR i : PixelsIndex;
BEGIN
s.u0 := u0; s.v0 := v0;
s.u1 := u1; s.v1 := v1;
FOR i := 0 TO MaxDrawingSurfaceSize - 1 DO
s.pixels[i] := 0.0
END
END InitializeDrawingSurface;
 
PROCEDURE DrawingSurfaceRef (VAR s : DrawingSurface;
x, y : DrawingSurfaceIndex) : REAL;
VAR c : REAL;
BEGIN
IF (s.u0 <= x) AND (x <= s.u1) AND (s.v0 <= y) AND (y <= s.v1) THEN
c := s.pixels[(x - s.u0) + ((s.v1 - y) * (s.u1 - s.u0 + 1))]
ELSE
(* (x,y) is outside the drawing surface. Return a somewhat
arbitrary value. "Not a number" would be better. *)
c := 0.0
END;
RETURN c
END DrawingSurfaceRef;
 
PROCEDURE DrawingSurfaceSet (VAR s : DrawingSurface;
x, y : DrawingSurfaceIndex;
c : REAL);
BEGIN
(* Store the value only if (x,y) is within the drawing surface. *)
IF (s.u0 <= x) AND (x <= s.u1) AND (s.v0 <= y) AND (y <= s.v1) THEN
s.pixels[(x - s.u0) + ((s.v1 - y) * (s.u1 - s.u0 + 1))] := c
END
END DrawingSurfaceSet;
 
PROCEDURE WriteTransparencyMask (VAR s : DrawingSurface);
VAR w, h : INTEGER;
i : DrawingSurfaceIndex;
byteval : [0 .. 255];
byte : SYSTEM.LOC;
BEGIN
(* Send to standard output a transparency map in raw Portable Gray
Map format. *)
w := s.u1 - s.u0 + 1;
h := s.v1 - s.v0 + 1;
STextIO.WriteString ('P5');
STextIO.WriteLn;
STextIO.WriteString ('# transparency mask');
STextIO.WriteLn;
SWholeIO.WriteCard (VAL (CARDINAL, w), 0);
STextIO.WriteString (' ');
SWholeIO.WriteCard (VAL (CARDINAL, h), 0);
STextIO.WriteLn;
STextIO.WriteString ('255');
STextIO.WriteLn;
FOR i := 0 TO (w * h) - 1 DO
byteval := RealMath.round (255.0 * s.pixels[i]);
byte := SYSTEM.CAST (SYSTEM.LOC, byteval);
SRawIO.Write (byte)
END
END WriteTransparencyMask;
 
PROCEDURE ipart (x : REAL) : INTEGER;
VAR i : INTEGER;
BEGIN
i := VAL (INTEGER, x);
IF x < VAL (REAL, i) THEN
i := i - 1;
END;
RETURN i
END ipart;
 
PROCEDURE iround (x : REAL) : INTEGER;
BEGIN
RETURN ipart (x + 0.5)
END iround;
 
PROCEDURE fpart (x : REAL) : REAL;
BEGIN
RETURN x - VAL (REAL, ipart (x))
END fpart;
 
PROCEDURE rfpart (x : REAL) : REAL;
BEGIN
RETURN 1.0 - fpart (x)
END rfpart;
 
PROCEDURE PlotShallow (VAR s : DrawingSurface;
x, y : INTEGER;
opacity : REAL);
VAR combined_opacity : REAL;
BEGIN
(* Let us simply add opacities, up to the maximum of 1.0. You might,
of course, wish to do something different. *)
combined_opacity := opacity + DrawingSurfaceRef (s, x, y);
IF combined_opacity > 1.0 THEN
combined_opacity := 1.0
END;
DrawingSurfaceSet (s, x, y, combined_opacity)
END PlotShallow;
 
PROCEDURE PlotSteep (VAR s : DrawingSurface;
x, y : INTEGER;
opacity : REAL);
BEGIN
PlotShallow (s, y, x, opacity)
END PlotSteep;
 
PROCEDURE drawln (VAR s : DrawingSurface;
x0, y0, x1, y1 : REAL;
plot : PointPlotter);
VAR dx, dy, gradient : REAL;
yend, xgap : REAL;
first_y_intersection, intery : REAL;
xend : INTEGER;
xpxl1, ypxl1 : INTEGER;
xpxl2, ypxl2 : INTEGER;
x : INTEGER;
BEGIN
dx := x1 - x0; dy := y1 - y0;
IF dx = 0.0 THEN
gradient := 1.0
ELSE
gradient := dy / dx
END;
 
(* Handle the first endpoint. *)
xend := iround (x0);
yend := y0 + (gradient * (VAL (REAL, xend) - x0));
xgap := rfpart (x0 + 0.5);
xpxl1 := xend;
ypxl1 := ipart (yend);
plot (s, xpxl1, ypxl1, rfpart (yend) * xgap);
plot (s, xpxl1, ypxl1 + 1, fpart (yend) * xgap);
 
first_y_intersection := yend + gradient;
 
(* Handle the second endpoint. *)
xend := iround (x1);
yend := y1 + (gradient * (VAL (REAL, xend) - x1));
xgap := fpart (x1 + 0.5);
xpxl2 := xend;
ypxl2 := ipart (yend);
plot (s, xpxl2, ypxl2, (rfpart (yend) * xgap));
plot (s, xpxl2, ypxl2 + 1, fpart (yend) * xgap);
 
(* Loop over the rest of the points. *)
intery := first_y_intersection;
FOR x := xpxl1 + 1 TO xpxl2 - 1 DO
plot (s, x, ipart (intery), rfpart (intery));
plot (s, x, ipart (intery) + 1, fpart (intery));
intery := intery + gradient
END
END drawln;
 
PROCEDURE DrawLine (VAR s : DrawingSurface;
x0, y0, x1, y1 : REAL);
VAR xdiff, ydiff : REAL;
BEGIN
xdiff := ABS (x1 - x0);
ydiff := ABS (y1 - y0);
IF ydiff <= xdiff THEN
IF x0 <= x1 THEN
drawln (s, x0, y0, x1, y1, PlotShallow)
ELSE
drawln (s, x1, y1, x0, y0, PlotShallow)
END
ELSE
IF y0 <= y1 THEN
drawln (s, y0, x0, y1, x1, PlotSteep)
ELSE
drawln (s, y1, x1, y0, x0, PlotSteep)
END
END
END DrawLine;
 
CONST u0 = -299;
u1 = 300;
v0 = -20;
v1 = 379;
CONST Kx = 4.0;
Ky = 0.1;
VAR s : DrawingSurface;
i : INTEGER;
t : REAL;
x0, y0, x1, y1 : REAL;
x, y, u, v : REAL;
BEGIN
InitializeDrawingSurface (s, u0, v0, u1, v1);
 
(* Draw a parabola. *)
FOR i := -101 TO 100 DO
t := VAL (REAL, i); x0 := Kx * t; y0 := Ky * t * t;
t := VAL (REAL, i + 1); x1 := Kx * t; y1 := Ky * t * t;
DrawLine (s, x0, y0, x1, y1)
END;
 
(* Draw normals to that parabola. The parabola has equation y=A*x*x,
where A=Ky/(Kx*Kx). Therefore the slope at x is dy/dx=2*A*x. The
slope of the normal is the negative reciprocal, and so equals
-1/(2*A*x)=-(Kx*Kx)/(2*Ky*(Kx*t))=-Kx/(2*Ky*t). *)
FOR i := -101 TO 101 DO
t := VAL (REAL, i);
x := Kx * t; y := Ky * t * t; (* (x,y) = a point on the parabola *)
IF ABS (t) <= 0.000000001 THEN (* (u,v) = a normal vector *)
u := 0.0; v := 1.0
ELSE
u := 1.0; v := -Kx / (2.0 * Ky * t)
END;
x0 := x - (1000.0 * u); y0 := y - (1000.0 * v);
x1 := x + (1000.0 * u); y1 := y + (1000.0 * v);
DrawLine (s, x0, y0, x1, y1);
END;
 
WriteTransparencyMask (s)
END Xiaolin_Wu_Task.
</syntaxhighlight>
 
Here is a shell script that compiles the program, runs it, and (using Netpbm commands) makes a PNG using the outputted mask.
 
<syntaxhighlight lang="sh">
#!/bin/sh
 
# Set GM2 to wherever you have a GNU Modula-2 compiler.
GM2="/usr/x86_64-pc-linux-gnu/gcc-bin/13/gm2"
 
${GM2} -g -fbounds-check -fiso xiaolin_wu_line_algorithm_Modula2.mod
./a.out > alpha.pgm
ppmmake rgb:5C/06/8C 600 400 > bg.ppm
ppmmake rgb:E2/E8/68 600 400 > fg.ppm
pamcomp -alpha=alpha.pgm fg.ppm bg.ppm | pamtopng > image.png
</syntaxhighlight>
 
{{out}}
[[File:Xiaolin wu line algorithm Modula2.png|thumb|none|alt=A parabola, and lines normal to the parabola, forming a semicubic parabola as their envelope. A shade of yellow on a background shade of purple.]]
 
=={{header|Nim}}==
Simple translation of the Wikipedia algorithm.
<langsyntaxhighlight Nimlang="nim">import math
import imageman
 
Line 2,219 ⟶ 3,787:
for x1 in countup(100, 700, 60):
img.drawLine(400, 700, x1.toFloat, 100)
img.savePNG("xiaoling_wu.png", compression = 9)</langsyntaxhighlight>
 
=={{header|ObjectIcon}}==
The program puts up a window. In the window you can draw a line by left-mouse-button-press for one endpoint, and then another press for the other endpoint. You can draw multiple lines. When you leave (by pressing "q", for instance, or closing the window), the program stores the image as a PNG.
 
Rather than vary the color as such, I vary the opacity.
 
<syntaxhighlight lang="objecticon">
import
graphics(Mouse, Window),
io(stop),
ipl.graphics(QuitEvents)
 
procedure main ()
local width, height
local done, w, event
local x1, y1, x2, y2, press_is_active
 
width := 640
height := 480
 
w := Window().
set_size(width, height).
set_bg("white").
set_canvas("normal") | stop(&why)
 
press_is_active := &no
done := &no
while /done do
{
if *w.pending() ~= 0 then
{
event := w.event()
case event[1] of
{
QuitEvents() : done := &yes
Mouse.LEFT_PRESS:
{
if /press_is_active then
{
x1 := event[2]; y1 := event[3]
press_is_active := &yes
}
else
{
x2 := event[2]; y2 := event[3]
draw_line (w, x1, y1, x2, y2)
press_is_active := &no
}
}
}
}
}
 
w.get_pixels().to_file("xiaolin_wu_line_algorithm_OI.png")
end
 
procedure draw_line (w, x0, y0, x1, y1)
local steep
local dx, dy, gradient
local xend, yend, xgap, intery
local xpxl1, ypxl1
local xpxl2, ypxl2
local x
 
x0 := real (x0)
y0 := real (y0)
x1 := real (x1)
y1 := real (y1)
 
# In Object Icon (as in Icon), comparisons DO NOT return boolean
# values! They either SUCCEED or they FAIL. Thus the need for an
# "if-then-else" here.
steep := if abs (y1 - y0) > abs (x1 - x0) then &yes else &no
 
if \steep then { x0 :=: y0; x1 :=: y1 }
if x0 > x1 then { x0 :=: x1; y0 :=: y1 }
dx := x1 - x0; dy := y1 - y0
gradient := if dx = 0 then 1.0 else dy / dx
 
# Handle the first endpoint.
xend := round (x0); yend := y0 + (gradient * (xend - x0))
xgap := rfpart (x0 + 0.5)
xpxl1 := xend; ypxl1 := ipart (yend)
if \steep then
{
plot (w, ypxl1, xpxl1, rfpart (yend) * xgap)
plot (w, ypxl1 + 1, xpxl1, fpart(yend) * xgap)
}
else
{
plot (w, xpxl1, ypxl1, rfpart (yend) * xgap)
plot (w, xpxl1, ypxl1 + 1, fpart (yend) * xgap)
}
 
# The first y-intersection.
intery := yend + gradient
 
# Handle the second endpoint.
xend := round (x1); yend := y1 + (gradient * (xend - x1))
xgap := fpart (x1 + 0.5)
xpxl2 := xend; ypxl2 := ipart (yend)
if \steep then
{
plot (w, ypxl2, xpxl2, rfpart (yend) * xgap)
plot (w, ypxl2 + 1, xpxl2, fpart (yend) * xgap)
}
else
{
plot (w, xpxl2, ypxl2, rfpart (yend) * xgap)
plot (w, xpxl2, ypxl2 + 1, fpart (yend) * xgap)
}
 
if \steep then
every x := xpxl1 + 1 to xpxl2 - 1 do
{
plot (w, ipart (intery), x, rfpart (intery))
plot (w, ipart (intery) + 1, x, fpart (intery))
intery := intery + gradient
}
else
every x := xpxl1 + 1 to xpxl2 - 1 do
{
plot(w, x, ipart (intery), rfpart (intery))
plot(w, x, ipart (intery) + 1, fpart (intery))
intery := intery + gradient
}
 
return
end
 
procedure plot (w, x, y, c)
w.set_fg ("black " || round (100.0 * c) || "%")
w.draw_point (x, y)
return
end
 
procedure ipart (x)
local i
i := integer (x)
return (if i = x then i else if x < 0 then i - 1 else i)
end
 
procedure round (x)
return ipart (x + 0.5)
end
 
procedure fpart (x)
return x - ipart (x)
end
 
procedure rfpart (x)
return 1.0 - fpart (x)
end
</syntaxhighlight>
 
{{out}}
An example:
[[File:Xiaolin wu line algorithm OI.2023.04.26.17.23.18.png|thumb|none|alt=Some straight lines, antialiased. Black on white.]]
 
=={{header|Pascal}}==
Line 2,226 ⟶ 3,952:
Based on Wikipwdia pseudocode with some optimizations and alpha handling.
 
<langsyntaxhighlight lang="pascal">
program wu;
uses
Line 2,349 ⟶ 4,075:
until false;
end.
</syntaxhighlight>
</lang>
 
=={{header|Perl}}==
This is mostly a translation of the pseudo-code on Wikipedia, except that the <code>$plot</code> trick was inspired by the Raku example.
<langsyntaxhighlight lang="perl">#!perl
use strict;
use warnings;
Line 2,431 ⟶ 4,157:
}
__END__
</syntaxhighlight>
</lang>
{{out}}
<pre>plot 0 1 0.5
Line 2,455 ⟶ 4,181:
 
=={{header|Phix}}==
For educational/comparison purposes only: see demo\pGUI\aaline.exw for a much shorter version.<br>
Resize the window to show lines at any angle
{{libheader|Phix/pGUI}}
{{libheader|Phix/online}}
<lang Phix>-- demo\rosetta\XiaolinWuLine.exw
You can run this online [http://phix.x10.mx/p2js/wuline.htm here], with caveats as below. Resize the window to show lines at any angle
constant TITLE = "Xiaolin Wu's line algorithm"
<!--<syntaxhighlight lang="phix">(phixonline)-->
 
<span style="color: #000080;font-style:italic;">--
bool bresline = false -- space toggles, for comparison
-- demo\rosetta\XiaolinWuLine.exw
 
-- ==============================
include pGUI.e
--
 
-- Resize the window to show lines at any angle
Ihandle dlg, canvas
--
cdCanvas cddbuffer, cdcanvas
-- For education/comparision purposes only: see demo\pGUI\aaline.exw
 
-- for a much shorter version, but "wrong algorithm" for the RC task.
constant BACK = CD_PARCHMENT,
-- Also note this blends with BACK rather than the actual pixel,
LINE = CD_BLUE,
-- whereas aaline.exw does it properly.
rB = red(BACK), gB = green(BACK), bB = blue(BACK),
--</span>
rL = red(LINE), gL = green(LINE), bL = blue(LINE)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- not really fair: pwa/p2js uses OpenGL
 
-- and does not draw bresenham lines anyway/ever, plus the next line
procedure plot(atom x, atom y, atom c, bool steep=false)
-- makes no difference whatsoever when running this in a browser.</span>
-- plot the pixel at (x, y) with brightness c (where 0 <= c <= 1)
<span style="color: #008080;">constant</span> <span style="color: #000000;">USE_OPENGL</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
if steep then {x,y} = {y,x} end if
atom C = 1-c
<span style="color: #008080;">constant</span> <span style="color: #000000;">TITLE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Xiaolin Wu's line algorithm"</span>
c = rgb(rL*c+rB*C,gL*c+gB*C,bL*c+bB*C)
cdCanvasPixel(cddbuffer, x, y, c)
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
end procedure
 
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span>
procedure plot2(atom x, atom y, atom f, atom xgap, bool steep)
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
plot(x,y,(1-f)*xgap,steep)
plot(x,y+1,f*xgap,steep)
<span style="color: #004080;">bool</span> <span style="color: #000000;">wuline</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span> <span style="color: #000080;font-style:italic;">-- space toggles, for comparison
end procedure
-- when false, and with USE_OPENGL, lines are still smooth,
 
-- but a bit thicker - and therefore less "ropey".
function fpart(atom x)
return x - floor(x) -- fractionalwhen false, but without USE_OPENGL, it partdraws ofbresenham x
-- lines (ie jagged, without anti-aliasing [desktop only]).</span>
end function
 
<span style="color: #004080;">integer</span> <span style="color: #000000;">BACK</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">CD_PARCHMENT</span><span style="color: #0000FF;">,</span>
procedure draw_line(atom x0,y0,x1,y1)
<span style="color: #000000;">LINE</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">CD_BLUE</span><span style="color: #0000FF;">,</span>
if bresline then
<span style="color: #0000FF;">{</span><span style="color: #000000;">rB</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">gB</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bB</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_rgb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">BACK</span><span style="color: #0000FF;">),</span>
cdCanvasLine(cddbuffer, x0, y0, x1, y1)
<span style="color: #0000FF;">{</span><span style="color: #000000;">rL</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">gL</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bL</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_rgb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">LINE</span><span style="color: #0000FF;">)</span>
return
end if
<span style="color: #008080;">procedure</span> <span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">steep</span><span style="color: #0000FF;">=</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
bool steep := abs(y1 - y0) > abs(x1 - x0)
<span style="color: #000080;font-style:italic;">-- plot the pixel at (x, y) with brightness c (where 0 &lt;= c &lt;= 1)</span>
if steep then
<span style="color: #008080;">if</span> <span style="color: #000000;">steep</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
{x0, y0, x1, y1} = {y0, x0, y1, x1}
<span style="color: #004080;">atom</span> <span style="color: #000000;">C</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">c</span>
end if
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rgb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rL</span><span style="color: #0000FF;">*</span><span style="color: #000000;">c</span><span style="color: #0000FF;">+</span><span style="color: #000000;">rB</span><span style="color: #0000FF;">*</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,</span><span style="color: #000000;">gL</span><span style="color: #0000FF;">*</span><span style="color: #000000;">c</span><span style="color: #0000FF;">+</span><span style="color: #000000;">gB</span><span style="color: #0000FF;">*</span><span style="color: #000000;">C</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bL</span><span style="color: #0000FF;">*</span><span style="color: #000000;">c</span><span style="color: #0000FF;">+</span><span style="color: #000000;">bB</span><span style="color: #0000FF;">*</span><span style="color: #000000;">C</span><span style="color: #0000FF;">)</span>
if x0>x1 then
<span style="color: #7060A8;">cdCanvasPixel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
{x0, x1, y0, y1} = {x1, x0, y1, y0}
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end if
<span style="color: #008080;">procedure</span> <span style="color: #000000;">plot2</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">xgap</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">steep</span><span style="color: #0000FF;">)</span>
atom dx := x1 - x0,
<span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">xgap</span><span style="color: #0000FF;">,</span><span style="color: #000000;">steep</span><span style="color: #0000FF;">)</span>
dy := y1 - y0,
<span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">xgap</span><span style="color: #0000FF;">,</span><span style="color: #000000;">steep</span><span style="color: #0000FF;">)</span>
gradient := iff(dx=0? 1 : dy / dx)
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
 
-- handle first endpoint
<span style="color: #008080;">function</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">)</span>
atom xend := round(x0),
<span style="color: #008080;">return</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- fractional part of x</span>
yend := y0 + gradient * (xend - x0),
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
xgap := 1-fpart(x0 + 0.5),
xpxl1 := xend, -- this will be used in the main loop
<span style="color: #008080;">procedure</span> <span style="color: #000000;">wu_line</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y1</span><span style="color: #0000FF;">)</span>
ypxl1 := floor(yend)
<span style="color: #004080;">bool</span> <span style="color: #000000;">steep</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">y0</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">)</span>
plot2(xpxl1, ypxl1, fpart(yend), xgap, steep)
<span style="color: #008080;">if</span> <span style="color: #000000;">steep</span> <span style="color: #008080;">then</span>
atom intery := yend + gradient -- first y-intersection for the main loop
<span style="color: #0000FF;">{</span><span style="color: #000000;">x0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">y0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x1</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
-- handle second endpoint
<span style="color: #008080;">if</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">></span><span style="color: #000000;">x1</span> <span style="color: #008080;">then</span>
xend := round(x1)
<span style="color: #0000FF;">{</span><span style="color: #000000;">x0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y0</span><span style="color: #0000FF;">}</span>
yend := y1 + gradient * (xend - x1)
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
xgap := fpart(x1 + 0.5)
atom xpxl2 := xend, -- this will be used in the main loop
<span style="color: #004080;">atom</span> <span style="color: #000000;">dx</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">x1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">,</span>
ypxl2 := floor(yend)
<span style="color: #000000;">dy</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">y1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">y0</span><span style="color: #0000FF;">,</span>
plot2(xpxl2, ypxl2, fpart(yend), xgap, steep)
<span style="color: #000000;">gradient</span> <span style="color: #0000FF;">:=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span> <span style="color: #000000;">1</span> <span style="color: #0000FF;">:</span> <span style="color: #000000;">dy</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">dx</span><span style="color: #0000FF;">)</span>
-- main loop
<span style="color: #000080;font-style:italic;">-- handle first endpoint</span>
for x = xpxl1+1 to xpxl2-1 do
<span style="color: #004080;">atom</span> <span style="color: #000000;">xend</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x0</span><span style="color: #0000FF;">),</span>
plot2(x, floor(intery), fpart(intery), 1, steep)
<span style="color: #000000;">yend</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">y0</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">gradient</span> <span style="color: #0000FF;">*</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">xend</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x0</span><span style="color: #0000FF;">),</span>
intery += gradient
<span style="color: #000000;">xgap</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">1</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x0</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">0.5</span><span style="color: #0000FF;">),</span>
end for
<span style="color: #000000;">xpxl1</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">xend</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- this will be used in the main loop</span>
end procedure
<span style="color: #000000;">ypxl1</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yend</span><span style="color: #0000FF;">)</span>
 
<span style="color: #000000;">plot2</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xpxl1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ypxl1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yend</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">xgap</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">steep</span><span style="color: #0000FF;">)</span>
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
<span style="color: #004080;">atom</span> <span style="color: #000000;">intery</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">yend</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">gradient</span> <span style="color: #000080;font-style:italic;">-- first y-intersection for the main loop
integer {w, h} = sq_sub(IupGetIntInt(canvas, "DRAWSIZE"),10)
cdCanvasActivate(cddbuffer)
-- handle second endpoint</span>
cdCanvasClear(cddbuffer)
<span style="color: #000000;">xend</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">)</span>
draw_line(0,0,200,200)
<span style="color: #000000;">yend</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">y1</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">gradient</span> <span style="color: #0000FF;">*</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">xend</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x1</span><span style="color: #0000FF;">)</span>
draw_line(w,0,200,200)
<span style="color: #000000;">xgap</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">0.5</span><span style="color: #0000FF;">)</span>
draw_line(0,h,200,200)
<span style="color: #004080;">atom</span> <span style="color: #000000;">xpxl2</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">xend</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- this will be used in the main loop</span>
draw_line(w,h,200,200)
<span style="color: #000000;">ypxl2</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yend</span><span style="color: #0000FF;">)</span>
cdCanvasFlush(cddbuffer)
<span style="color: #000000;">plot2</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xpxl2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ypxl2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yend</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">xgap</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">steep</span><span style="color: #0000FF;">)</span>
return IUP_DEFAULT
end function
<span style="color: #000080;font-style:italic;">-- main loop</span>
 
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">xpxl1</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">xpxl2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
function map_cb(Ihandle ih)
<span style="color: #000000;">plot2</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">intery</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">intery</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">steep</span><span style="color: #0000FF;">)</span>
cdcanvas = cdCreateCanvas(CD_IUP, ih)
<span style="color: #000000;">intery</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">gradient</span>
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
cdCanvasSetBackground(cddbuffer, BACK)
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
cdCanvasSetForeground(cddbuffer, LINE)
return IUP_DEFAULT
<span style="color: #008080;">procedure</span> <span style="color: #000000;">plot_4_points</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle1</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;">=</span><span style="color: #000000;">360</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
end function
<span style="color: #004080;">integer</span> <span style="color: #000000;">x1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span>
 
<span style="color: #000000;">y1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">-</span><span style="color: #000000;">y</span>
function esc_close(Ihandle /*ih*/, atom c)
<span style="color: #008080;">if</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">></span><span style="color: #000000;">90.01</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if c=K_ESC then return IUP_CLOSE end if
<span style="color: #008080;">if</span> <span style="color: #000000;">angle</span> <span style="color: #0000FF;">>=</span><span style="color: #000000;">angle1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">angle</span> <span style="color: #0000FF;"><=</span><span style="color: #000000;">angle2</span> <span style="color: #008080;">then</span> <span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- top right</span>
if c=' ' then
<span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">180</span><span style="color: #0000FF;">-</span><span style="color: #000000;">angle</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">angle1</span> <span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">180</span><span style="color: #0000FF;">-</span><span style="color: #000000;">angle</span><span style="color: #0000FF;">)<=</span><span style="color: #000000;">angle2</span> <span style="color: #008080;">then</span> <span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- top left</span>
bresline = not bresline
<span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">180</span><span style="color: #0000FF;">+</span><span style="color: #000000;">angle</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">angle1</span> <span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">180</span><span style="color: #0000FF;">+</span><span style="color: #000000;">angle</span><span style="color: #0000FF;">)<=</span><span style="color: #000000;">angle2</span> <span style="color: #008080;">then</span> <span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- btm left</span>
IupRedraw(canvas)
<span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">360</span><span style="color: #0000FF;">-</span><span style="color: #000000;">angle</span><span style="color: #0000FF;">)>=</span><span style="color: #000000;">angle1</span> <span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">360</span><span style="color: #0000FF;">-</span><span style="color: #000000;">angle</span><span style="color: #0000FF;">)<=</span><span style="color: #000000;">angle2</span> <span style="color: #008080;">then</span> <span style="color: #000000;">plot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- btm right</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
return IUP_CONTINUE
end function
<span style="color: #008080;">procedure</span> <span style="color: #000000;">wu_ellipse</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle1</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;">=</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
 
<span style="color: #000080;font-style:italic;">--
procedure main()
-- (draws a circle when w=h) credit:
IupOpen()
-- https://yellowsplash.wordpress.com/2009/10/23/fast-antialiased-circles-and-ellipses-from-xiaolin-wus-concepts/
canvas = IupCanvas(NULL)
--</span>
IupSetAttribute(canvas, "RASTERSIZE", "640x480")
<span style="color: #008080;">if</span> <span style="color: #000000;">w</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">h</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
<span style="color: #000000;">cx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cx</span><span style="color: #0000FF;">)</span>
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
<span style="color: #000000;">cy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cy</span><span style="color: #0000FF;">)</span>
dlg = IupDialog(canvas)
<span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">)</span>
IupSetAttribute(dlg, "TITLE", TITLE)
<span style="color: #000000;">h</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)</span>
IupSetCallback(dlg, "K_ANY", Icallback("esc_close"))
<span style="color: #000000;">angle1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">angle1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
IupShow(dlg)
<span style="color: #000000;">angle2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">angle2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
IupSetAttribute(canvas, "RASTERSIZE", NULL)
IupMainLoop()
<span style="color: #000080;font-style:italic;">-- Match cdCanvasArc/Sector angles:</span>
IupClose()
<span style="color: #000000;">angle1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">atan2</span><span style="color: #0000FF;">((</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">angle1</span><span style="color: #0000FF;">*</span><span style="color: #004600;">CD_DEG2RAD</span><span style="color: #0000FF;">),</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">angle1</span><span style="color: #0000FF;">*</span><span style="color: #004600;">CD_DEG2RAD</span><span style="color: #0000FF;">))*</span><span style="color: #004600;">CD_RAD2DEG</span>
end procedure
<span style="color: #000000;">angle2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">atan2</span><span style="color: #0000FF;">((</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">angle2</span><span style="color: #0000FF;">*</span><span style="color: #004600;">CD_DEG2RAD</span><span style="color: #0000FF;">),</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">angle2</span><span style="color: #0000FF;">*</span><span style="color: #004600;">CD_DEG2RAD</span><span style="color: #0000FF;">))*</span><span style="color: #004600;">CD_RAD2DEG</span>
main()</lang>
<span style="color: #008080;">if</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">angle1</span> <span style="color: #008080;">then</span> <span style="color: #000000;">angle2</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">360</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">asq</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">*</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bsq</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">*</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">sqab</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">asq</span><span style="color: #0000FF;">+</span><span style="color: #000000;">bsq</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">ffd</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">asq</span><span style="color: #0000FF;">/</span><span style="color: #000000;">sqab</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- forty-five-degree coord</span>
<span style="color: #000000;">xj</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">yj</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">frc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">flr</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle</span>
<span style="color: #000080;font-style:italic;">-- draw top right, and the 3 mirrors of it in horizontal fashion
-- (ie 90 to 45 degrees for a circle)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">xi</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">ffd</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">yj</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">xi</span><span style="color: #0000FF;">*</span><span style="color: #000000;">xi</span><span style="color: #0000FF;">/</span><span style="color: #000000;">asq</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- real y value</span>
<span style="color: #000000;">frc</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yj</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">flr</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yj</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">angle</span> <span style="color: #0000FF;">:=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xi</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">90</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yj</span><span style="color: #0000FF;">/</span><span style="color: #000000;">xi</span><span style="color: #0000FF;">)*</span><span style="color: #004600;">CD_RAD2DEG</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">plot_4_points</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">xi</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">flr</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">frc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">plot_4_points</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">xi</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">flr</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">frc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000080;font-style:italic;">-- switch from horizontal to vertial mode for the rest, ditto 3
-- (ie 45..0 degrees for a circle)</span>
<span style="color: #000000;">ffd</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bsq</span><span style="color: #0000FF;">/</span><span style="color: #000000;">sqab</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">yi</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">ffd</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">xj</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">yi</span><span style="color: #0000FF;">*</span><span style="color: #000000;">yi</span><span style="color: #0000FF;">/</span><span style="color: #000000;">bsq</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- real x value</span>
<span style="color: #000000;">frc</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">fpart</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xj</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">flr</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xj</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">angle</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">xj</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">arctan</span><span style="color: #0000FF;">(</span><span style="color: #000000;">yi</span><span style="color: #0000FF;">/</span><span style="color: #000000;">xj</span><span style="color: #0000FF;">)*</span><span style="color: #004600;">CD_RAD2DEG</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">plot_4_points</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">flr</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">yi</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">frc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">plot_4_points</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">flr</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">yi</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">frc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">angle</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">),</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">cdCanvasSetLineWidth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wuline</span><span style="color: #0000FF;">?</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #000000;">4</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wuline</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">wu_line</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">wu_line</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">wu_line</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">wu_line</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wuline</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">wu_ellipse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- cdCanvasSector(cddbuffer, 200, 200, 200, 200, 0, 360) </span>
<span style="color: #000000;">wu_ellipse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span><span style="color: #000000;">300</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- wu_ellipse(200,200,300,100,15,85)
-- cdCanvasArc(cddbuffer, 205, 205, 300, 100, 15, 85) </span>
<span style="color: #008080;">else</span>
<span style="color: #7060A8;">cdCanvasArc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- cdCanvasSector(cddbuffer, 200, 200, 200, 200, 0, 360) </span>
<span style="color: #7060A8;">cdCanvasArc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">300</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">--test - it works (much better) if you draw the polygon /after/ the lines!!
-- cdCanvasBegin(cddbuffer,CD_FILL)
-- cdCanvasVertex(cddbuffer,w,h)
-- cdCanvasVertex(cddbuffer,0,h)
-- cdCanvasVertex(cddbuffer,200,200)
-- cdCanvasEnd(cddbuffer)
--/test</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">USE_OPENGL</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupGLSwapBuffers</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">USE_OPENGL</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupGLMakeCurrent</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_GL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"10x10 %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cdcanvas</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">BACK</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">LINE</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">canvas_resize_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*canvas*/</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">USE_OPENGL</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">canvas_width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas_height</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetDouble</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SCREENDPI"</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">25.4</span>
<span style="color: #7060A8;">cdCanvasSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"%dx%d %g"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">canvas_width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas_height</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">set_title</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">TITLE</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">USE_OPENGL</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">title</span> <span style="color: #0000FF;">&=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wuline</span><span style="color: #0000FF;">?</span><span style="color: #008000;">" (wu_line)"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">" (opengl)"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">title</span> <span style="color: #0000FF;">&=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wuline</span><span style="color: #0000FF;">?</span><span style="color: #008000;">" (anti-aliased)"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">" (bresenham)"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">title</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">wuline</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">not</span> <span style="color: #000000;">wuline</span>
<span style="color: #000000;">set_title</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupRedraw</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">USE_OPENGL</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGLCanvas</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"BUFFER"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DOUBLE"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"640x480"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"RESIZE_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"canvas_resize_cb"</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">set_title</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"KEY_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(scl 2)
 
(de plot (Img X Y C)
Line 2,633 ⟶ 4,513:
(prinl 120 " " 90)
(prinl 100)
(for Y Img (apply printsp Y)) ) )</langsyntaxhighlight>
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">Macro PlotB(x, y, Color, b)
Plot(x, y, RGB(Red(Color) * (b), Green(Color) * (b), Blue(Color) * (b)))
EndMacro
Line 2,707 ⟶ 4,587:
Repeat
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow</langsyntaxhighlight>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">"""Script demonstrating drawing of anti-aliased lines using Xiaolin Wu's line
algorithm
 
Line 2,729 ⟶ 4,609:
 
def putpixel(img, xy, color, alpha=1):
"""
"""Paints color over the background at the point xy in img.
Paints color over the background at the point xy in img.
Use alpha for blending. alpha=1 means a completely opaque foreground.
 
"""
ccompose_color = tuple(map(lambda bg, fg: int(round(alpha * fg + (1-alpha) * bg)),
c = compose_color(img.getpixel(xy), color))
img.putpixel(xy, c)
 
Line 2,787 ⟶ 4,666:
filename = sys.argv[1]
img.save(filename)
print 'image saved to', filename</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">#lang racket
(require 2htdp/image)
 
Line 2,873 ⟶ 4,752:
img-2
(save-image img-1 "images/xiaolin-wu-racket-1.png")
(save-image img-2 "images/xiaolin-wu-racket-2.png")</langsyntaxhighlight>
 
Output files:
Line 2,881 ⟶ 4,760:
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" perl6line>sub plot(\x, \y, \c) { say "plot {x} {y} {c}" }
sub fpart(\x) { x - floor(x) }
Line 2,940 ⟶ 4,819:
}
 
draw-line [0,1], [10,2];</langsyntaxhighlight>
{{out}}
<pre>plot 0 1 1
Line 2,975 ⟶ 4,854:
<br>Also, it takes in account (that can easily be overlooked) of the note after the description of the algorithm:
<br>'''Note''': &nbsp; If at the beginning of the routine &nbsp; abs(''dx'') < abs(''dy'') &nbsp; is true, then all plotting should be done with &nbsp; '''x''' &nbsp; and &nbsp; '''y''' &nbsp; reversed.
<langsyntaxhighlight lang="rexx">/*REXX program plots/draws (ASCII) a line using the Xiaolin Wu line algorithm. */
background= '·' /*background character: a middle-dot. */
image.= background /*fill the array with middle-dots. */
Line 3,034 ⟶ 4,913:
plotXY: 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</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 3,059 ⟶ 4,938:
=={{header|Ruby}}==
{{trans|Tcl}}
<langsyntaxhighlight lang="ruby">def ipart(n); n.truncate; end
def fpart(n); n - ipart(n); end
def rfpart(n); 1.0 - fpart(n); end
Line 3,125 ⟶ 5,004:
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)</langsyntaxhighlight>
 
=={{header|Scala}}==
Uses [[Bitmap#Scala]].
<langsyntaxhighlight Scalalang="scala">import java.awt.Color
import math.{floor => ipart, round, abs}
 
Line 3,197 ⟶ 5,076:
intery = intery + gradient
}
}</langsyntaxhighlight>
'''Example:'''
 
Test line drawing in various directions including vertical, horizontal, 45° and oblique (such lines are drawn multiple times to test swapped parameters).
<langsyntaxhighlight Scalalang="scala">val r = 120
val img = new RgbBitmap(r*2+1, r*2+1)
val line = drawLine(plotter(img, Color.GRAY)_)_
Line 3,210 ⟶ 5,089:
line(a, b)
}
javax.imageio.ImageIO.write(img.image, "png", new java.io.File("XiaolinWuLineAlgorithm.png"))</langsyntaxhighlight>
{{out}}
View the PNG, available at the following URL because RosettaCode image uploads were disabled:
https://lh5.googleusercontent.com/GxBAHV4nebuO1uiKboKc6nQmmtlJV47jPwVZnQHcbV7TKm0kjdKfKteclCfxmSdFJnSKvYYoB5I
 
=={{header|Scheme}}==
{{trans|ATS}}
{{works with|CHICKEN Scheme|5.3.0}}
{{works with|Gauche Scheme|0.9.12}}
 
This program is written for R7RS. For CHICKEN you need the '''r7rs''' and '''srfi-160''' eggs.
 
<syntaxhighlight lang="scheme">
;;;-------------------------------------------------------------------
 
(import (scheme base))
(import (scheme file))
(import (scheme inexact))
(import (scheme process-context))
(import (scheme write))
 
;; (srfi 160 f32) is more properly known as (scheme vector f32), but
;; is not part of R7RS-small. The following will work in both Gauche
;; and CHICKEN Schemes.
(import (srfi 160 f32))
 
;;;-------------------------------------------------------------------
 
(define-record-type <color>
(make-color r g b)
color?
(r color-r)
(g color-g)
(b color-b))
 
;;; See https://yeun.github.io/open-color/
(define violet9 (make-color (/ #x5F 255.0)
(/ #x3D 255.0)
(/ #xC4 255.0)))
 
;;;-------------------------------------------------------------------
 
(define-record-type <drawing-surface>
(drawing-surface% u0 v0 u1 v1 pixels)
drawing-surface?
(u0 u0%)
(v0 v0%)
(u1 u1%)
(v1 v1%)
(pixels pixels%))
 
(define (make-drawing-surface u0 v0 u1 v1)
(unless (and (<= u0 u1) (<= v0 v1))
(error "illegal drawing-surface corners"))
(let ((width (- u1 u0 -1))
(height (- v1 v0 -1)))
(let ((pixels (make-f32vector (* width height) 0.0)))
(drawing-surface% u0 v0 u1 v1 pixels))))
 
;;; In calls to drawing-surface-ref and drawing-surface-set! indices
;;; outside the drawing_surface are allowed. Such indices are treated
;;; as if you were trying to draw on the air.
 
(define (drawing-surface-ref s x y)
(let ((u0 (u0% s))
(v0 (v0% s))
(u1 (u1% s))
(v1 (v1% s)))
(if (and (<= u0 x) (<= x u1) (<= v0 y) (<= y v1))
(f32vector-ref (pixels% s)
(+ (* (- x u0) (- v1 v0 -1)) (- v1 y)))
+nan.0)))
 
(define (drawing-surface-set! s x y opacity)
(let ((u0 (u0% s))
(v0 (v0% s))
(u1 (u1% s))
(v1 (v1% s)))
(when (and (<= u0 x) (<= x u1) (<= v0 y) (<= y v1))
(f32vector-set! (pixels% s)
(+ (* (- x u0) (- v1 v0 -1)) (- v1 y))
opacity))))
 
(define (write-PAM s color)
;; Write a Portable Arbitrary Map to the current output port, using
;; the given color as the foreground color and the drawing-surface
;; values as opacities.
 
(define (float->byte v) (exact (round (* 255 v))))
 
(define r (float->byte (color-r color)))
(define g (float->byte (color-g color)))
(define b (float->byte (color-b color)))
 
(define w (- (u1% s) (u0% s) -1))
(define h (- (v1% s) (v0% s) -1))
(define opacities (pixels% s))
 
(define (loop x y)
(cond ((= y h) )
((= x w) (loop 0 (+ y 1)))
(else
(let ((alpha (float->byte
(f32vector-ref opacities (+ (* x h) y)))))
(write-bytevector (bytevector r g b alpha))
(loop (+ x 1) y)))))
 
(display "P7") (newline)
(display "WIDTH ") (display (- (u1% s) (u0% s) -1)) (newline)
(display "HEIGHT ") (display (- (v1% s) (v0% s) -1)) (newline)
(display "DEPTH 4") (newline)
(display "MAXVAL 255") (newline)
(display "TUPLTYPE RGB_ALPHA") (newline)
(display "ENDHDR") (newline)
(loop 0 0))
 
;;;-------------------------------------------------------------------
 
(define (ipart x) (exact (floor x)))
(define (iround x) (ipart (+ x 0.5)))
(define (fpart x) (- x (floor x)))
(define (rfpart x) (- 1.0 (fpart x)))
 
(define (plot s x y opacity)
;; One might prefer a more sophisticated function than mere
;; addition. Here, however, the function is addition.
(let ((combined-opacity (+ opacity (drawing-surface-ref s x y))))
(drawing-surface-set! s x y (min combined-opacity 1.0))))
 
(define (drawln% s x0 y0 x1 y1 steep)
(let* ((dx (- x1 x0))
(dy (- y1 y0))
(gradient (if (zero? dx) 1.0 (/ dy dx)))
 
;; Handle the first endpoint.
(xend (iround x0))
(yend (+ y0 (* gradient (- xend x0))))
(xgap (rfpart (+ x0 0.5)))
(xpxl1 xend)
(ypxl1 (ipart yend))
(_ (if steep
(begin
(plot s ypxl1 xpxl1 (* (rfpart yend) xgap))
(plot s (+ ypxl1 1) xpxl1 (* (fpart yend) xgap)))
(begin
(plot s xpxl1 ypxl1 (* (rfpart yend) xgap))
(plot s xpxl1 (+ ypxl1 1) (* (fpart yend) xgap)))))
 
;; The first y-intersection.
(intery (+ yend gradient))
 
;; Handle the second endpoint.
(xend (iround x1))
(yend (+ y1 (* gradient (- xend x1))))
(xgap (fpart (+ x1 0.5)))
(xpxl2 xend)
(ypxl2 (ipart yend))
(_ (if steep
(begin
(plot s ypxl2 xpxl2 (* (rfpart yend) xgap))
(plot s (+ ypxl2 1) xpxl2 (* (fpart yend) xgap)))
(begin
(plot s xpxl2 ypxl2 (* (rfpart yend) xgap))
(plot s xpxl2 (+ ypxl2 1) (* (fpart yend) xgap))))))
 
;; Loop over the rest of the points.
(if steep
(do ((x (+ xpxl1 1) (+ x 1))
(intery intery (+ intery gradient)))
((= x xpxl2))
(plot s (ipart intery) x (rfpart intery))
(plot s (+ (ipart intery) 1) x (fpart intery)))
(do ((x (+ xpxl1 1) (+ x 1))
(intery intery (+ intery gradient)))
((= x xpxl2))
(plot s x (ipart intery) (rfpart intery))
(plot s x (+ (ipart intery) 1) (fpart intery))))))
 
(define (draw-line s x0 y0 x1 y1)
(let ((xdiff (abs (- x1 x0)))
(ydiff (abs (- y1 y0))))
(if (<= ydiff xdiff)
(if (<= x0 x1)
;; R7RS lets you say #false and #true, as equivalents of
;; #f and #t. (To support such things as #false and #true,
;; the "r7rs" egg for CHICKEN Scheme 5 comes with a
;; special reader.)
(drawln% s x0 y0 x1 y1 #false)
(drawln% s x1 y1 x0 y0 #false))
(if (<= y0 y1)
(drawln% s y0 x0 y1 x1 #true)
(drawln% s y1 x1 y0 x0 #true)))))
 
;;;-------------------------------------------------------------------
 
(define u0 0)
(define v0 0)
(define u1 999)
(define v1 749)
 
(define PI (* 4.0 (atan 1.0)))
(define PI/180 (/ PI 180.0))
 
(define (cosdeg theta) (cos (* theta PI/180)))
(define (sindeg theta) (sin (* theta PI/180)))
 
(define s (make-drawing-surface u0 v0 u1 v1))
 
;; The values of theta are exactly representable in either binary or
;; decimal floating point, and therefore the following loop will NOT
;; do the angle zero twice. (If you might stray from exact
;; representations, you must do something different, such as increment
;; an integer.)
(let ((x0 (inexact (* (/ 380 640) u1)))
(y0 (inexact (* (/ 130 480) v1))))
(do ((theta 0.0 (+ theta 5.0)))
((<= 360.0 theta))
(let ((cos-theta (cosdeg theta))
(sin-theta (sindeg theta)))
(let ((x1 (+ x0 (* cos-theta 1200.0)))
(y1 (+ y0 (* sin-theta 1200.0))))
(draw-line s x0 y0 x1 y1)))))
 
(define args (command-line))
(unless (= (length args) 2)
(parameterize ((current-output-port (current-error-port)))
(display (string-append "Usage: " (car args) " FILENAME"))
(newline)
(display (string-append " " (car args) " -"))
(newline) (newline)
(display (string-append "The second form writes the PAM file"
" to standard output."))
(newline)
(exit 1)))
(if (string=? (cadr args) "-")
(write-PAM s violet9)
(with-output-to-file (list-ref args 1)
(lambda () (write-PAM s violet9))))
 
;;;-------------------------------------------------------------------
</syntaxhighlight>
 
{{out}}
The output of the program is a Portable Arbitrary Map, defining a transparent image of the drawn lines. Here is an example of making a complete PNG image from such a PAM (using CHICKEN Scheme):
<pre>
$ csc -O5 -R r7rs -X r7rs xiaolin_wu_line_algorithm.scm
$ ./xiaolin_wu_line_algorithm image.pam
$ pamgradient lightgray lightblue lightcyan lightgray 1000 750 | pamcomp image.pam - | pamtopng > image.png
</pre>
Here is what I get:
[[File:Xiaolin wu line algorithm SCM.2023.04.28.14.08.55.png|thumb|none|alt=A violet starburst on a light bluish gradient background.]]
 
 
I thought it would be amusing to modify the code to use the R7RS-small macro system, and so I made the following second version. Note also the variable <code>steep</code> is gone.
<syntaxhighlight lang="scheme">
;;;-------------------------------------------------------------------
 
(import (scheme base))
(import (scheme file))
(import (scheme inexact))
(import (scheme process-context))
(import (scheme write))
 
;; (srfi 160 f32) is more properly known as (scheme vector f32), but
;; is not part of R7RS-small. The following will work in both Gauche
;; and CHICKEN Schemes.
(import (srfi 160 f32))
 
;;;-------------------------------------------------------------------
 
(define-record-type <color>
(make-color r g b)
color?
(r color-r)
(g color-g)
(b color-b))
 
;;; See https://yeun.github.io/open-color/
(define violet9 (make-color (/ #x5F 255.0)
(/ #x3D 255.0)
(/ #xC4 255.0)))
 
;;;-------------------------------------------------------------------
 
(define-record-type <drawing-surface>
(drawing-surface% u0 v0 u1 v1 pixels)
drawing-surface?
(u0 u0%)
(v0 v0%)
(u1 u1%)
(v1 v1%)
(pixels pixels%))
 
(define (make-drawing-surface u0 v0 u1 v1)
(unless (and (<= u0 u1) (<= v0 v1))
(error "illegal drawing-surface corners"))
(let ((width (- u1 u0 -1))
(height (- v1 v0 -1)))
(let ((pixels (make-f32vector (* width height) 0.0)))
(drawing-surface% u0 v0 u1 v1 pixels))))
 
;;; In calls to drawing-surface-ref and drawing-surface-set! indices
;;; outside the drawing_surface are allowed. Such indices are treated
;;; as if you were trying to draw on the air.
 
(define (drawing-surface-ref s x y)
(let ((u0 (u0% s))
(v0 (v0% s))
(u1 (u1% s))
(v1 (v1% s)))
(if (and (<= u0 x) (<= x u1) (<= v0 y) (<= y v1))
(f32vector-ref (pixels% s)
(+ (* (- x u0) (- v1 v0 -1)) (- v1 y)))
+nan.0)))
 
(define (drawing-surface-set! s x y opacity)
(let ((u0 (u0% s))
(v0 (v0% s))
(u1 (u1% s))
(v1 (v1% s)))
(when (and (<= u0 x) (<= x u1) (<= v0 y) (<= y v1))
(f32vector-set! (pixels% s)
(+ (* (- x u0) (- v1 v0 -1)) (- v1 y))
opacity))))
 
(define (write-PAM s color)
;; Write a Portable Arbitrary Map to the current output port, using
;; the given color as the foreground color and the drawing-surface
;; values as opacities.
 
(define (float->byte v) (exact (round (* 255 v))))
 
(define r (float->byte (color-r color)))
(define g (float->byte (color-g color)))
(define b (float->byte (color-b color)))
 
(define w (- (u1% s) (u0% s) -1))
(define h (- (v1% s) (v0% s) -1))
(define opacities (pixels% s))
 
(define (loop x y)
(cond ((= y h) )
((= x w) (loop 0 (+ y 1)))
(else
(let ((alpha (float->byte
(f32vector-ref opacities (+ (* x h) y)))))
(write-bytevector (bytevector r g b alpha))
(loop (+ x 1) y)))))
 
(display "P7") (newline)
(display "WIDTH ") (display (- (u1% s) (u0% s) -1)) (newline)
(display "HEIGHT ") (display (- (v1% s) (v0% s) -1)) (newline)
(display "DEPTH 4") (newline)
(display "MAXVAL 255") (newline)
(display "TUPLTYPE RGB_ALPHA") (newline)
(display "ENDHDR") (newline)
(loop 0 0))
 
;;;-------------------------------------------------------------------
 
(define-syntax ipart
(syntax-rules ()
((_ x) (exact (floor x)))))
 
(define-syntax iround
(syntax-rules ()
((_ x) (ipart (+ x 0.5)))))
 
(define-syntax fpart
(syntax-rules ()
((_ x) (- x (floor x)))))
 
(define-syntax rfpart
(syntax-rules ()
((_ x) (- 1.0 (fpart x)))))
 
(define-syntax plot-shallow
(syntax-rules ()
((_ s x y opacity)
;; One might prefer a more sophisticated function than mere
;; addition. Here, however, the function is addition.
(let ((combined-opacity (+ opacity (drawing-surface-ref s x y))))
(drawing-surface-set! s x y (min combined-opacity 1.0))))))
 
(define-syntax plot-steep
(syntax-rules ()
((_ s x y opacity)
(plot-shallow s y x opacity))))
 
(define-syntax drawln%
(syntax-rules ()
((_ s x0 y0 x1 y1 plot)
(let* ((dx (- x1 x0))
(dy (- y1 y0))
(gradient (if (zero? dx) 1.0 (/ dy dx)))
 
;; Handle the first endpoint.
(xend (iround x0))
(yend (+ y0 (* gradient (- xend x0))))
(xgap (rfpart (+ x0 0.5)))
(xpxl1 xend)
(ypxl1 (ipart yend))
(_ (plot s xpxl1 ypxl1 (* (rfpart yend) xgap)))
(_ (plot s xpxl1 (+ ypxl1 1) (* (fpart yend) xgap)))
 
;; The first y-intersection.
(intery (+ yend gradient))
 
;; Handle the second endpoint.
(xend (iround x1))
(yend (+ y1 (* gradient (- xend x1))))
(xgap (fpart (+ x1 0.5)))
(xpxl2 xend)
(ypxl2 (ipart yend))
(_ (plot s xpxl2 ypxl2 (* (rfpart yend) xgap)))
(_ (plot s xpxl2 (+ ypxl2 1) (* (fpart yend) xgap))))
 
;; Loop over the rest of the points.
(do ((x (+ xpxl1 1) (+ x 1))
(intery intery (+ intery gradient)))
((= x xpxl2))
(plot s x (ipart intery) (rfpart intery))
(plot s x (+ (ipart intery) 1) (fpart intery)))))))
 
(define (draw-line s x0 y0 x1 y1)
(let ((xdiff (abs (- x1 x0)))
(ydiff (abs (- y1 y0))))
(if (<= ydiff xdiff)
(if (<= x0 x1)
(drawln% s x0 y0 x1 y1 plot-shallow)
(drawln% s x1 y1 x0 y0 plot-shallow))
(if (<= y0 y1)
(drawln% s y0 x0 y1 x1 plot-steep)
(drawln% s y1 x1 y0 x0 plot-steep)))))
 
;;;-------------------------------------------------------------------
 
(define u0 0)
(define v0 0)
(define u1 999)
(define v1 749)
 
(define PI (* 4.0 (atan 1.0)))
(define PI/180 (/ PI 180.0))
 
(define (cosdeg theta) (cos (* theta PI/180)))
(define (sindeg theta) (sin (* theta PI/180)))
 
(define s (make-drawing-surface u0 v0 u1 v1))
 
;; The values of theta are exactly representable in either binary or
;; decimal floating point, and therefore the following loop will NOT
;; do the angle zero twice. (If you might stray from exact
;; representations, you must do something different, such as increment
;; an integer.)
(let ((x0 (inexact (* (/ 380 640) u1)))
(y0 (inexact (* (/ 130 480) v1))))
(do ((theta 0.0 (+ theta 5.0)))
((<= 360.0 theta))
(let ((cos-theta (cosdeg theta))
(sin-theta (sindeg theta)))
(let ((x1 (+ x0 (* cos-theta 1200.0)))
(y1 (+ y0 (* sin-theta 1200.0))))
(draw-line s x0 y0 x1 y1)))))
 
(define args (command-line))
(unless (= (length args) 2)
(parameterize ((current-output-port (current-error-port)))
(display (string-append "Usage: " (car args) " FILENAME"))
(newline)
(display (string-append " " (car args) " -"))
(newline) (newline)
(display (string-append "The second form writes the PAM file"
" to standard output."))
(newline)
(exit 1)))
(if (string=? (cadr args) "-")
(write-PAM s violet9)
(with-output-to-file (list-ref args 1)
(lambda () (write-PAM s violet9))))
 
;;;-------------------------------------------------------------------
</syntaxhighlight>
 
=={{header|Sidef}}==
{{trans|Perl}}
<langsyntaxhighlight lang="ruby">func plot(x, y, c) {
c && printf("plot %d %d %.1f\n", x, y, c);
}
Line 3,274 ⟶ 5,632:
}
 
drawLine(0, 1, 10, 2);</langsyntaxhighlight>
{{out}}
<pre>
Line 3,300 ⟶ 5,658:
 
=={{header|Swift}}==
<langsyntaxhighlight lang="swift">import Darwin
// apply pixel of color at x,y with an OVER blend to the bitmap
public func pixel(color: Color, x: Int, y: Int) {
Line 3,393 ⟶ 5,751:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Tcl}}==
{{libheader|Tk}}
Uses code from [[Basic bitmap storage#Tcl]]
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
package require Tk
 
Line 3,485 ⟶ 5,843:
toplevel .wu
label .wu.l -image $img
pack .wu.l</langsyntaxhighlight>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|DOME}}
<langsyntaxhighlight ecmascriptlang="wren">import "graphics" for Canvas, Color
import "dome" for Window
import "math" for Math
Line 3,580 ⟶ 5,938:
}
 
var Game = XiaolinWu.new(640, 640)</langsyntaxhighlight>
 
=={{header|Yabasic}}==
{{trans|Phix}}
<langsyntaxhighlight Yabasiclang="yabasic">bresline = false // space toggles, for comparison
rB = 255 : gB = 255 : bB = 224
Line 3,667 ⟶ 6,025:
draw_line(w, 0, 200, 200)
draw_line(0, h, 200, 200)
draw_line(w, h, 200, 200)</langsyntaxhighlight>
 
[[Category:Geometry]]
9,476

edits