September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -0,0 +1,101 @@
|
|||
// version 1.1.2
|
||||
|
||||
import java.awt.*
|
||||
import javax.swing.*
|
||||
|
||||
class XiaolinWu: JPanel() {
|
||||
init {
|
||||
preferredSize = Dimension(640, 640)
|
||||
background = Color.white
|
||||
}
|
||||
|
||||
private fun plot(g: Graphics2D, x: Double, y: Double, c: Double) {
|
||||
g.color = Color(0f, 0f, 0f, c.toFloat())
|
||||
g.fillOval(x.toInt(), y.toInt(), 2, 2)
|
||||
}
|
||||
|
||||
private fun ipart(x: Double) = x.toInt()
|
||||
|
||||
private fun fpart(x: Double) = x - Math.floor(x)
|
||||
|
||||
private fun rfpart(x: Double) = 1.0 - fpart(x)
|
||||
|
||||
private fun drawLine(g: Graphics2D, x0: Double, y0: Double, x1: Double, y1: Double) {
|
||||
val steep = Math.abs(y1 - y0) > Math.abs(x1 - x0)
|
||||
if (steep) drawLine(g, y0, x0, y1, x1)
|
||||
if (x0 > x1) drawLine(g, x1, y1, x0, y0)
|
||||
|
||||
val dx = x1 - x0
|
||||
val dy = y1 - y0
|
||||
val gradient = dy / dx
|
||||
|
||||
// handle first endpoint
|
||||
var xend = Math.round(x0).toDouble()
|
||||
var yend = y0 + gradient * (xend - x0)
|
||||
var xgap = rfpart(x0 + 0.5)
|
||||
val xpxl1 = xend // this will be used in the main loop
|
||||
val ypxl1 = ipart(yend).toDouble()
|
||||
|
||||
if (steep) {
|
||||
plot(g, ypxl1, xpxl1, rfpart(yend) * xgap)
|
||||
plot(g, ypxl1 + 1.0, xpxl1, fpart(yend) * xgap)
|
||||
}
|
||||
else {
|
||||
plot(g, xpxl1, ypxl1, rfpart(yend) * xgap)
|
||||
plot(g, xpxl1, ypxl1 + 1.0, fpart(yend) * xgap)
|
||||
}
|
||||
|
||||
// first y-intersection for the main loop
|
||||
var intery = yend + gradient
|
||||
|
||||
// handle second endpoint
|
||||
xend = Math.round(x1).toDouble()
|
||||
yend = y1 + gradient * (xend - x1)
|
||||
xgap = fpart(x1 + 0.5)
|
||||
val xpxl2 = xend // this will be used in the main loop
|
||||
val ypxl2 = ipart(yend).toDouble()
|
||||
|
||||
if (steep) {
|
||||
plot(g, ypxl2, xpxl2, rfpart(yend) * xgap)
|
||||
plot(g, ypxl2 + 1.0, xpxl2, fpart(yend) * xgap)
|
||||
}
|
||||
else {
|
||||
plot(g, xpxl2, ypxl2, rfpart(yend) * xgap)
|
||||
plot(g, xpxl2, ypxl2 + 1.0, fpart(yend) * xgap)
|
||||
}
|
||||
|
||||
// main loop
|
||||
var x = xpxl1 + 1.0
|
||||
while (x <= xpxl2 - 1) {
|
||||
if (steep) {
|
||||
plot(g, ipart(intery).toDouble(), x, rfpart(intery))
|
||||
plot(g, ipart(intery).toDouble() + 1.0, x, fpart(intery))
|
||||
}
|
||||
else {
|
||||
plot(g, x, ipart(intery).toDouble(), rfpart(intery))
|
||||
plot(g, x, ipart(intery).toDouble() + 1.0, fpart(intery))
|
||||
}
|
||||
intery += gradient
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
||||
override protected fun paintComponent(gg: Graphics) {
|
||||
super.paintComponent(gg)
|
||||
val g = gg as Graphics2D
|
||||
drawLine(g, 550.0, 170.0, 50.0, 435.0)
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
SwingUtilities.invokeLater {
|
||||
val f = JFrame()
|
||||
f.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
|
||||
f.title = "Xiaolin Wu's line algorithm"
|
||||
f.isResizable = false
|
||||
f.add(XiaolinWu(), BorderLayout.CENTER)
|
||||
f.pack()
|
||||
f.setLocationRelativeTo(null)
|
||||
f.isVisible = true
|
||||
}
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ sub draw-line(@a is copy, @b is copy) {
|
|||
for (x-pxl1 + 1 .. x-pxl2 - 1)
|
||||
Z
|
||||
(intery, intery + gradient ... *)
|
||||
-> \x,\y {
|
||||
-> (\x,\y) {
|
||||
my \c = fpart(y);
|
||||
$plot(x, floor(y) , 1 - c) unless c == 1;
|
||||
$plot(x, floor(y) + 1, c ) unless c == 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
--
|
||||
-- demo\rosetta\XiaolinWuLine.exw
|
||||
-- ==============================
|
||||
--
|
||||
constant TITLE = "Xiaolin Wu's line algorithm"
|
||||
|
||||
bool bresline = false -- space toggles, for comparison
|
||||
|
||||
include pGUI.e
|
||||
|
||||
Ihandle dlg, canvas
|
||||
cdCanvas cddbuffer, cdcanvas
|
||||
|
||||
constant BACK = CD_PARCHMENT,
|
||||
LINE = CD_BLUE,
|
||||
rB = red(BACK), gB = green(BACK), bB = blue(BACK),
|
||||
rL = red(LINE), gL = green(LINE), bL = blue(LINE)
|
||||
|
||||
procedure plot(atom x, atom y, atom c, bool steep=false)
|
||||
-- plot the pixel at (x, y) with brightness c (where 0 <= c <= 1)
|
||||
if steep then {x,y} = {y,x} end if
|
||||
atom C = 1-c
|
||||
c = rgb(rL*c+rB*C,gL*c+gB*C,bL*c+bB*C)
|
||||
cdCanvasPixel(cddbuffer, x, y, c)
|
||||
end procedure
|
||||
|
||||
procedure plot2(atom x, atom y, atom f, atom xgap, bool steep)
|
||||
plot(x,y,(1-f)*xgap,steep)
|
||||
plot(x,y+1,f*xgap,steep)
|
||||
end procedure
|
||||
|
||||
function fpart(atom x)
|
||||
return x - floor(x) -- fractional part of x
|
||||
end function
|
||||
|
||||
procedure draw_line(atom x0,y0,x1,y1)
|
||||
if bresline then
|
||||
cdCanvasLine(cddbuffer, x0, y0, x1, y1)
|
||||
return
|
||||
end if
|
||||
bool steep := abs(y1 - y0) > abs(x1 - x0)
|
||||
if steep then
|
||||
{x0, y0, x1, y1} = {y0, x0, y1, x1}
|
||||
end if
|
||||
if x0>x1 then
|
||||
{x0, x1, y0, y1} = {x1, x0, y1, y0}
|
||||
end if
|
||||
|
||||
atom dx := x1 - x0,
|
||||
dy := y1 - y0,
|
||||
gradient := iff(dx=0? 1 : dy / dx)
|
||||
|
||||
-- handle first endpoint
|
||||
atom xend := round(x0),
|
||||
yend := y0 + gradient * (xend - x0),
|
||||
xgap := 1-fpart(x0 + 0.5),
|
||||
xpxl1 := xend, -- this will be used in the main loop
|
||||
ypxl1 := floor(yend)
|
||||
plot2(xpxl1, ypxl1, fpart(yend), xgap, steep)
|
||||
atom intery := yend + gradient -- first y-intersection for the main loop
|
||||
|
||||
-- handle second endpoint
|
||||
xend := round(x1)
|
||||
yend := y1 + gradient * (xend - x1)
|
||||
xgap := fpart(x1 + 0.5)
|
||||
atom xpxl2 := xend, -- this will be used in the main loop
|
||||
ypxl2 := floor(yend)
|
||||
plot2(xpxl2, ypxl2, fpart(yend), xgap, steep)
|
||||
|
||||
-- main loop
|
||||
for x = xpxl1+1 to xpxl2-1 do
|
||||
plot2(x, floor(intery), fpart(intery), 1, steep)
|
||||
intery += gradient
|
||||
end for
|
||||
end procedure
|
||||
|
||||
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
|
||||
integer {w, h} = sq_sub(IupGetIntInt(canvas, "DRAWSIZE"),10)
|
||||
cdCanvasActivate(cddbuffer)
|
||||
cdCanvasClear(cddbuffer)
|
||||
draw_line(0,0,200,200)
|
||||
draw_line(w,0,200,200)
|
||||
draw_line(0,h,200,200)
|
||||
draw_line(w,h,200,200)
|
||||
cdCanvasFlush(cddbuffer)
|
||||
return IUP_DEFAULT
|
||||
end function
|
||||
|
||||
function map_cb(Ihandle ih)
|
||||
cdcanvas = cdCreateCanvas(CD_IUP, ih)
|
||||
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
|
||||
cdCanvasSetBackground(cddbuffer, BACK)
|
||||
cdCanvasSetForeground(cddbuffer, LINE)
|
||||
return IUP_DEFAULT
|
||||
end function
|
||||
|
||||
function esc_close(Ihandle /*ih*/, atom c)
|
||||
if c=K_ESC then return IUP_CLOSE end if
|
||||
if c=' ' then
|
||||
bresline = not bresline
|
||||
IupRedraw(canvas)
|
||||
end if
|
||||
return IUP_CONTINUE
|
||||
end function
|
||||
|
||||
procedure main()
|
||||
IupOpen()
|
||||
canvas = IupCanvas(NULL)
|
||||
IupSetAttribute(canvas, "RASTERSIZE", "640x480")
|
||||
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
|
||||
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
|
||||
dlg = IupDialog(canvas)
|
||||
IupSetAttribute(dlg, "TITLE", TITLE)
|
||||
IupSetCallback(dlg, "K_ANY", Icallback("esc_close"))
|
||||
IupShow(dlg)
|
||||
IupSetAttribute(canvas, "RASTERSIZE", NULL)
|
||||
IupMainLoop()
|
||||
IupClose()
|
||||
end procedure
|
||||
main()
|
||||
|
|
@ -1,63 +1,60 @@
|
|||
/*REXX program plots/draws a line using the Xiaolin Wu line algorithm. */
|
||||
background='·' /*background character: a middle-dot. */
|
||||
image.=background /*fill the array with middle-dots. */
|
||||
plotC='░▒▓█' /*characters used for plotting points. */
|
||||
EoE=1000 /*EOE = End Of Earth, er, ··· graph. */
|
||||
do j=-EoE to +EoE /*define the graph: lowest ──► highest.*/
|
||||
image.j.0='─' /*define the graph's horizontal axis. */
|
||||
image.0.j='│' /* " " " verical " */
|
||||
end /*j*/
|
||||
image.0.0='┼' /*define the graph's axis origin (char)*/
|
||||
parse arg xi yi xf yf . /*allow specifying the line-end points.*/
|
||||
if xi=='' | xi=="," then xi= 1 /*Not specified? Then use the default.*/
|
||||
if yi=='' | yi=="," then yi= 2 /* " " " " " " */
|
||||
if xf=='' | xf=="," then xf=11 /* " " " " " " */
|
||||
if yf=='' | yf=="," then yf=12 /* " " " " " " */
|
||||
minX=0; minY=0 /*use these as the limits for plotting.*/
|
||||
maxX=0; maxY=0 /* " " " " " " " */
|
||||
call drawLine xi, yi, xf, yf /*invoke subroutine and graph the line.*/
|
||||
border=2 /*allow additional space (plot border).*/
|
||||
minX=minX-border*2; maxX=maxX+border*2 /* *2 preserves screen's aspect ratio.*/
|
||||
minY=minY-border ; maxY=maxY+border
|
||||
do y=maxY by -1 to minY; _= /*build a row.*/
|
||||
do x=minX to maxX; _=_ || image.x.y; end /*x*/
|
||||
say _ /*display row.*/
|
||||
end /*y*/ /*graph is cropped by the MINs and MAXs*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
/*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. */
|
||||
plotC= '░▒▓█' /*characters used for plotting points. */
|
||||
EoE= 3000 /*EOE = End Of Earth, er, ··· graph. */
|
||||
do j=-EoE to +EoE /*define the graph: lowest ──► highest.*/
|
||||
image.j.0= '─' /*define the graph's horizontal axis. */
|
||||
image.0.j= '│' /* " " " verical " */
|
||||
end /*j*/
|
||||
image.0.0= '┼' /*define the graph's axis origin (char)*/
|
||||
parse arg xi yi xf yf . /*allow specifying the line-end points.*/
|
||||
if xi=='' | xi=="," then xi= 1 /*Not specified? Then use the default.*/
|
||||
if yi=='' | yi=="," then yi= 2 /* " " " " " " */
|
||||
if xf=='' | xf=="," then xf=11 /* " " " " " " */
|
||||
if yf=='' | yf=="," then yf=12 /* " " " " " " */
|
||||
minX=0; minY=0 /*use these as the limits for plotting.*/
|
||||
maxX=0; maxY=0 /* " " " " " " " */
|
||||
call drawLine xi, yi, xf, yf /*invoke subroutine and graph the line.*/
|
||||
border=2 /*allow additional space (plot border).*/
|
||||
minX=minX - border * 2; maxX=maxX+border * 2 /*preserve screen's aspect ratio {*2}.*/
|
||||
minY=minY - border ; maxY=maxY+border
|
||||
do y=maxY to minY by -1; _= /*construct a row.*/
|
||||
do x=minX to maxX; _=_ || image.x.y; end /*x*/
|
||||
say _ /*display the constructed row to term. */
|
||||
end /*y*/ /*graph is cropped by the MINs and MAXs*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
drawLine: parse arg x1,y1,x2,y2; switchXY=0; dx=x2-x1
|
||||
dy=y2-y1
|
||||
if abs(dx) < abs(dy) then parse value x1 y1 x2 y2 dx dy with,
|
||||
y1 x2 y2 x2 dy dx
|
||||
if x2<x1 then parse value x1 x2 y1 y2 1 with,
|
||||
x2 x1 y2 y1 switchXY
|
||||
if abs(dx)<abs(dy) then parse value x1 y1 x2 y2 dx dy with y1 x2 y2 x2 dy dx
|
||||
if x2<x1 then parse value x1 x2 y1 y2 1 with x2 x1 y2 y1 switchXY
|
||||
gradient=dy/dx
|
||||
xend=round(x1) /*◄─────────────────1st endpoint.══════════════*/
|
||||
yend=y1 + gradient*(xend-x1); xgap=1-fpart(x1 + .5)
|
||||
xend=round(x1) /*◄─────────────────1st endpoint.══════════════*/
|
||||
yend=y1 + gradient * (xend-x1); xgap=1 - fpart(x1 + .5)
|
||||
xpx11=xend; ypx11=floor(yend)
|
||||
intery=yend+gradient
|
||||
call plotXY xpx11, ypx11, brite(1-fpart(yend*xgap)), switchXY
|
||||
call plotXY xpx11, ypx11+1, brite( fpart(yend*xgap)), switchXY
|
||||
xend=round(x2) /*◄─────────────────2nd endpoint.══════════════*/
|
||||
yend=y2 + gradient*(xend-x2); xgap=fpart(x2 + .5)
|
||||
call plotXY xpx11, ypx11, brite(1 - fpart(yend*xgap)), switchXY
|
||||
call plotXY xpx11, ypx11+1, brite( fpart(yend*xgap)), switchXY
|
||||
xend=round(x2) /*◄─────────────────2nd endpoint.══════════════*/
|
||||
yend=y2 + gradient * (xend-x2); xgap= fpart(x2 + .5)
|
||||
xpx12=xend; ypx12=floor(yend)
|
||||
call plotXY xpx12, ypx12 , brite(1-fpart(yend*xgap)), switchXY
|
||||
call plotXY xpx12, ypx12+1, brite( fpart(yend*xgap)), switchXY
|
||||
call plotXY xpx12, ypx12 , brite(1 - fpart(yend*xgap)), switchXY
|
||||
call plotXY xpx12, ypx12+1, brite( fpart(yend*xgap)), switchXY
|
||||
|
||||
do x=xpx11+1 to xpx12-1 /*◄───draw the line.═════════════*/
|
||||
do x=xpx11+1 to xpx12-1 /*◄───draw the line.═════════════*/
|
||||
!intery=floor(intery)
|
||||
call plotXY x, !intery , brite(1-fpart(intery)), switchXY
|
||||
call plotXY x, !intery+1, brite( fpart(intery)), switchXY
|
||||
intery=intery+gradient
|
||||
call plotXY x, !intery , brite(1 - fpart(intery)), switchXY
|
||||
call plotXY x, !intery+1, brite( fpart(intery)), switchXY
|
||||
intery=intery + gradient
|
||||
end /*x*/
|
||||
return
|
||||
/*────────────────────────────────short subroutines and functions.────────────*/
|
||||
brite: return substr(background||plotC, 1+round(abs(arg(1))*length(plotC)),1)
|
||||
floor: parse arg ?; _=trunc(?); return _ - (?<0) * (?\=_)
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
brite: return substr(background || plotC, 1 + round( abs( arg(1) ) * length(plotC)), 1)
|
||||
floor: parse arg ?; _=trunc(?); return _ - (?<0) * (?\=_)
|
||||
fpart: parse arg ?; return abs(? - trunc(?))
|
||||
round: return format(arg(1), , word(arg(2) 0, 1))
|
||||
|
||||
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
|
||||
round: return format(arg(1), , word(arg(2) 0, 1) )
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
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) {
|
||||
let idx = x + y * self.width
|
||||
if idx >= 0 && idx < self.bitmap.count {
|
||||
self.bitmap[idx] = self.blendColors(bot: self.bitmap[idx], top: color)
|
||||
}
|
||||
}
|
||||
|
||||
// return the fractional part of a Double
|
||||
func fpart(_ x: Double) -> Double {
|
||||
return modf(x).1
|
||||
}
|
||||
|
||||
// reciprocal of the fractional part of a Double
|
||||
func rfpart(_ x: Double) -> Double {
|
||||
return 1 - fpart(x)
|
||||
}
|
||||
|
||||
// draw a 1px wide line using Xiolin Wu's antialiased line algorithm
|
||||
public func smoothLine(_ p0: Point, _ p1: Point) {
|
||||
var x0 = p0.x, x1 = p1.x, y0 = p0.y, y1 = p1.y //swapable ptrs
|
||||
let steep = abs(y1 - y0) > abs(x1 - x0)
|
||||
if steep {
|
||||
swap(&x0, &y0)
|
||||
swap(&x1, &y1)
|
||||
}
|
||||
if x0 > x1 {
|
||||
swap(&x0, &x1)
|
||||
swap(&y0, &y1)
|
||||
}
|
||||
let dX = x1 - x0
|
||||
let dY = y1 - y0
|
||||
|
||||
var gradient: Double
|
||||
if dX == 0.0 {
|
||||
gradient = 1.0
|
||||
}
|
||||
else {
|
||||
gradient = dY / dX
|
||||
}
|
||||
|
||||
// handle endpoint 1
|
||||
var xend = round(x0)
|
||||
var yend = y0 + gradient * (xend - x0)
|
||||
var xgap = self.rfpart(x0 + 0.5)
|
||||
let xpxl1 = Int(xend)
|
||||
let ypxl1 = Int(yend)
|
||||
|
||||
// first y-intersection for the main loop
|
||||
var intery = yend + gradient
|
||||
|
||||
if steep {
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.rfpart(yend) * xgap), x: ypxl1, y: xpxl1)
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.fpart(yend) * xgap), x: ypxl1 + 1, y: xpxl1)
|
||||
}
|
||||
else {
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.rfpart(yend) * xgap), x: xpxl1, y: ypxl1)
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.fpart(yend) * xgap), x: xpxl1, y: ypxl1 + 1)
|
||||
}
|
||||
|
||||
xend = round(x1)
|
||||
yend = y1 + gradient * (xend - x1)
|
||||
xgap = self.fpart(x1 + 0.5)
|
||||
let xpxl2 = Int(xend)
|
||||
let ypxl2 = Int(yend)
|
||||
|
||||
// handle second endpoint
|
||||
if steep {
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.rfpart(yend) * xgap), x: ypxl2, y: xpxl2)
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.fpart(yend) * xgap), x: ypxl2 + 1, y: xpxl2)
|
||||
}
|
||||
else {
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.rfpart(yend) * xgap), x: xpxl2, y: ypxl2)
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.fpart(yend) * xgap), x: xpxl2, y: ypxl2 + 1)
|
||||
}
|
||||
|
||||
// main loop
|
||||
if steep {
|
||||
for x in xpxl1+1..<xpxl2 {
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.rfpart(intery)), x: Int(intery), y: x)
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.fpart(intery)), x: Int(intery) + 1, y:x)
|
||||
intery += gradient
|
||||
}
|
||||
}
|
||||
else {
|
||||
for x in xpxl1+1..<xpxl2 {
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.rfpart(intery)), x: x, y: Int(intery))
|
||||
self.pixel(color: self.strokeColor.colorWithAlpha(self.fpart(intery)), x: x, y: Int(intery) + 1)
|
||||
intery += gradient
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue