(好不容易排好版,结果复制上来就又乱了)
“在数学上,理想的直线是没有宽度的,它是由无数个点构成的集合”。在计算机图形 学中,绘制线宽为一个像素的直线有三种常用算法:数值微分法(DDA)、中点画线法和 Bresenham 算法。这里,我是用 Java 中的 Applet 来实现中点画线算法。
设画直线过程中当前像素点为(𝑥𝑝,𝑦𝑝),下一个像素点有两个选择点𝑃1(𝑥𝑝 +1, 𝑦𝑝)或 𝑃2(𝑥𝑝+1 , 𝑦𝑝+1)。取中点 M=(𝑥𝑝+1 , 𝑦𝑝+0.5),Q 为理想直线与𝑥𝑝 +1 的交点。当 M 在 Q 的上 方时,取下点𝑃2;当 M 在 Q 点的下方时,取上点𝑃1。
直线的方程为F = (x,y) = ax + by + c = 0 ,a = 𝑦0 − 𝑦1,b = 𝑥1 − 𝑥0,c = 𝑥0𝑦1 − 𝑥1𝑦0 ,想要判断 M 在 Q 点的上方还是下方
(I)斜率小于 1 时:
需要构造判别式 d = F(M) = F(𝑥𝑝 + 1,𝑦𝑝 + 0.5) = 𝑎(𝑥𝑝 + 1) + 𝑏(𝑦𝑝 + 0.5) + c.
设从点(𝑥0,𝑦0)开始画线,d 的初值𝑑0 = F(𝑥0 + 1,𝑦0 + 0.5) = F(𝑥0,𝑦0) + 𝑎 + 0.5𝑏,因为 F(𝑥0,𝑦0) = 0,所以𝑑0 = 𝑎 + 0.5𝑏.
(1) 当d ≥ 0时,取正右方像素𝑃1(𝑥𝑝 +1, 𝑦𝑝)。判断下一个像素的位置时,应计算 𝑑1 = 𝐹(𝑥𝑝 + 2,𝑦𝑝 + 0.5) = 𝑎(𝑥𝑝 + 2) + 𝑏(𝑦𝑝 + 0.5) + c = d + a,增量为 a;
(2) 当d < 0时,取右上方像素𝑃2(𝑥𝑝 +1, 𝑦𝑝 + 1)。判断下一个像素的位置时,应计算 𝑑2 = 𝐹(𝑥𝑝 + 2,𝑦𝑝 + 1.5) = 𝑎(𝑥𝑝 + 2) + 𝑏(𝑦𝑝 + 1.5) + c = d + a + b,增量为 a+b;
(II)斜率大于 1 时:
需要构造判别式 d = F(M) = F(𝑥𝑝 + 0.5,𝑦𝑝 + 1) = 𝑎(𝑥𝑝 + 0.5) + 𝑏(𝑦𝑝 + 1) + c.
设从点(𝑥0,𝑦0)开始画线,d 的初值𝑑0 = F(𝑥0 + 0.5,𝑦0 + 1) = F(𝑥0,𝑦0) + 0.5𝑎 + 𝑏,因为 F(𝑥0,𝑦0) = 0,所以𝑑0 = 0.5𝑎 + 𝑏.
(1) 当d < 0时,取正上方像素𝑃1(𝑥𝑝 , 𝑦𝑝 + 1)。判断下一个像素的位置时,应计算 𝑑1 = 𝐹(𝑥𝑝 + 0.5,𝑦𝑝 + 2) = 𝑎(𝑥𝑝 + 0.5) + 𝑏(𝑦𝑝 + 2) + c = d + b,增量为 b;
(2) 当d ≥ 0时,取右上方像素𝑃2(𝑥𝑝 +1, 𝑦𝑝 + 1)。判断下一个像素的位置时,应计算 𝑑2 = 𝐹(𝑥𝑝 + 1.5,𝑦𝑝 + 2) = 𝑎(𝑥𝑝 + 1.5) + 𝑏(𝑦𝑝 + 2) + c = d + a + b,增量为 a+b;
控制台输入起始点和终止点坐标,applet程序呈现绘图
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Scanner;
public class MidPoint extends Applet {
int a[] = new int[4];
public void init() {
setSize(300, 300);
Scanner sc = new Scanner(System.in);
System.out.println("input two point");
for (int i = 0; i < 4; i++) {
a[i] = sc.nextInt();
}
}
public void paint(Graphics g) {
g.setColor(Color.pink);
for (int i = 10; i <= 210; i += 10) {
g.drawLine(i, 10, i, 210);// 竖线
g.drawLine(10, i, 210, i);// 横线
}
g.setColor(Color.BLACK);
g.drawLine(10, 210, 220, 210);// x坐标
g.drawLine(10, 0, 10, 210);// y坐标
int x0 = a[0];
int y0 = a[1];
int x1 = a[2];
int y1 = a[3];
int a, b, d1, d2, d, x, y;
a = y0 - y1;
b = x1 - x0;
if (Math.abs(a / b) <= 1) {// 斜率绝对值小于1
d = 2 * a + b;
d1 = 2 * a;
d2 = 2 * (a + b);
} else {// 大于1
d = a + 2 * b;
d1 = 2 * b;
d2 = 2 * (a + b);
}
x = x0;
y = y0;
g.drawOval(x * 10 - 2 + 10, 210 - y * 10 - 2, 4, 4);// 起始点
if (Math.abs(a / b) <= 1) {// 斜率小于1
while (x < x1) {
if (d < 0) {
x++;
y++;
d += d2;
} else {
x++;
d += d1;
}
g.drawOval(x * 10 - 2 + 10, 210 - y * 10 - 2, 4, 4);// 描点
}
} else {// 斜率大于1
while (y < y1) {
if (d > 0) {
x++;
y++;
d += d2;
} else {
y++;
d += d1;
}
g.drawOval(x * 10 - 2 + 10, 210 - y * 10 - 2, 4, 4);// 描点
}
}
g.drawLine(x0 * 10 + 10, 210 - y0 * 10, x * 10 + 10, 210 - y * 10);// 画直线
}
}