Xiaolin Wu's line algorithm: Difference between revisions
Content added Content deleted
Line 1,381: | Line 1,381: | ||
end |
end |
||
bitmap.draw_line_antialised(Pixel[10, 10], Pixel[490,490], RGBColour::YELLOW)</lang> |
bitmap.draw_line_antialised(Pixel[10, 10], Pixel[490,490], RGBColour::YELLOW)</lang> |
||
=={{header|Scala}}== |
|||
Uses [[Bitmap#Scala]]. |
|||
<lang Scala>import java.awt.Color |
|||
import math.{floor => ipart, round, abs} |
|||
case class Point(x: Double, y: Double) {def swap = Point(y, x)} |
|||
def plotter(bm: RgbBitmap, c: Color)(x: Double, y: Double, v: Double) = { |
|||
val X = round(x).toInt |
|||
val Y = round(y).toInt |
|||
val V = v.toFloat |
|||
// tint the existing pixels |
|||
val c1 = c.getRGBColorComponents(null) |
|||
val c2 = bm.getPixel(X, Y).getRGBColorComponents(null) |
|||
val c3 = (c1 zip c2).map{case (n, o) => n * V + o * (1 - V)} |
|||
bm.setPixel(X, Y, new Color(c3(0), c3(1), c3(2))) |
|||
} |
|||
def drawLine(plotter: (Double,Double,Double) => _)(p1: Point, p2: Point) { |
|||
def fpart(x: Double) = x - ipart(x) |
|||
def rfpart(x: Double) = 1 - fpart(x) |
|||
def avg(a: Float, b: Float) = (a + b) / 2 |
|||
val steep = abs(p2.y - p1.y) > abs(p2.x - p1.x) |
|||
val (p3, p4) = if (steep) (p1.swap, p2.swap) else (p1, p2) |
|||
val (a, b) = if (p3.x > p4.x) (p4, p3) else (p3, p4) |
|||
val dx = b.x - a.x |
|||
val dy = b.y - a.y |
|||
val gradient = dy / dx |
|||
var intery = 0.0 |
|||
def endpoint(xpxl: Double, yend: Double, xgap: Double) { |
|||
val ypxl = ipart(yend) |
|||
if (steep) { |
|||
plotter(ypxl, xpxl, rfpart(yend) * xgap) |
|||
plotter(ypxl+1, xpxl, fpart(yend) * xgap) |
|||
} else { |
|||
plotter(xpxl, ypxl , rfpart(yend) * xgap) |
|||
plotter(xpxl, ypxl+1, fpart(yend) * xgap) |
|||
} |
|||
} |
|||
// handle first endpoint |
|||
var xpxl1 = round(a.x); |
|||
{ |
|||
val yend = a.y + gradient * (xpxl1 - a.x) |
|||
val xgap = rfpart(a.x + 0.5) |
|||
endpoint(xpxl1, yend, xgap) |
|||
intery = yend + gradient |
|||
} |
|||
// handle second endpoint |
|||
val xpxl2 = round(b.x); |
|||
{ |
|||
val yend = b.y + gradient * (xpxl2 - b.x) |
|||
val xgap = fpart(b.x + 0.5) |
|||
endpoint(xpxl2, yend, xgap) |
|||
} |
|||
// main loop |
|||
for (x <- (xpxl1 + 1) to (xpxl2 - 1)) { |
|||
if (steep) { |
|||
plotter(ipart(intery) , x, rfpart(intery)) |
|||
plotter(ipart(intery)+1, x, fpart(intery)) |
|||
} else { |
|||
plotter(x, ipart (intery), rfpart(intery)) |
|||
plotter(x, ipart (intery)+1, fpart(intery)) |
|||
} |
|||
intery = intery + gradient |
|||
} |
|||
}</lang> |
|||
'''Example:''' |
|||
Test line drawing in various directions including vertical, horizontal, 45° and oblique (such lines are drawn multiple times to test swapped parameters). |
|||
<lang Scala>val r = 120 |
|||
val img = new RgbBitmap(r*2+1, r*2+1) |
|||
val line = drawLine(plotter(img, Color.GRAY)_)_ |
|||
img.fill(Color.WHITE) |
|||
for (angle <- 0 to 360 by 30; θ = math toRadians angle; θ2 = θ + math.Pi) { |
|||
val a = Point(r + r * math.sin(θ), r + r * math.cos(θ)) |
|||
val b = Point(r + r * math.sin(θ2), r + r * math.cos(θ2)) |
|||
line(a, b) |
|||
} |
|||
javax.imageio.ImageIO.write(img.image, "png", new java.io.File("XiaolinWuLineAlgorithm.png"))</lang> |
|||
{{out}} |
|||
View the PNG, available at the following URL because RosettaCode image uploads were disabled: |
|||
https://lh5.googleusercontent.com/GxBAHV4nebuO1uiKboKc6nQmmtlJV47jPwVZnQHcbV7TKm0kjdKfKteclCfxmSdFJnSKvYYoB5I |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |