MiddlePoint
MiddlePoint算法:代中点入直线的隐式方程中,然后判定正负
假定直线的斜率在0到1之间(直线和x轴的夹角小于45°),x=x(i)时已选(x(i), y(i))像素,此时x=x(i)+1与直线最近的像素P1(x(i)+1, y1(i))、P2(x(i)+1), y(i)+1)。
假定M是表示P1与P2的中点,M=(x(i)+1, y(i)+0.5),Q是直线与垂直线x=x(i)+1的交点,如果M在Q的下方,那么P2离直线更近,应该取为下一个像素点;如果M在Q点上方,则P1离直线更近,应该取为下一个像素点;如果M和Q重合,习惯地取P1为下一个像素点(运算更快)。
假设起点和终点分别为(x0, y0)和(x1, y1),隐式方程为F(x, y) = ax + by + c,可以用待定系数法求出:
a = y0 - y1
b = x1 - x0
c = x0y1 - x1y0
直线上的点,F(x, y) = 0;
直线上方的点,F(x, y) > 0;
直线下方的点,F(x, y) < 0。
将M=(x(i)+1, y(i)+0.5)代入隐式方程F(x, y),d = F(M) = F(x(i)+1, y(i)+0.5) = a(x(i)+1) + b(y(i)+0.5) + c
当d<0时,M在直线下方,所以选取右上方的P2点;
当d>0时,M在直线上方,所以选取右上方的P1点;
当d=0时,M在直线上,选取P1点。
对每一个像素进行判别式d,根据d的符号确定下一像素:
若d>=0,取P1,去了之后再判断下一个像素,计算:d1 = F(x(i)+2, y(i)+0.5) = a(x(i)+2) + b(y(i)+0.5) + c = d + a,d的增量为a;
若d<0,取P2,同理:d2 = d + a + b,d的增量为a + b。
再看看d的初始值,显然,第一个像素应取为左端点(x0, y0),相应的判别式值为:d0 = F(x0+1, y0 + 0.5) = F(x0, y0) + a + 0.5b = a + 0.5b;
因此,d的初始值为d0 = a + 0.5b,此处为了避免浮点数运算,可以使用2d来替代d。(2d = 2a + b)
手动画点举个例子:
关键部分代码实现:
void MidPointLine(int x0, int y0, int x1, int y1)
{
int a, b, d1, d2, d, x, y;
a = y0 - y1;
b = x1 - x0;
d = 2 * a + b;
d1 = 2 * a;
d2 = 2 * (a + b);
x = x0;
y = y0;
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
while (x < x1)
{
if (d < 0)
{
x++;
y++;
d += d2;
}
else
{
x++;
d += d1;
}
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
}
}
测试结果:
完整代码:
#include <GL/glut.h>
#include <math.h>
/*
void DDA_Line(int x1, int y1, int x2, int y2) {
double dx, dy, e, x, y;
dx = x2 - x1;
dy = y2 - y1;
e = (fabs(dx) > fabs(dy)) ? fabs(dx) : fabs(dy);
dx /= e;
dy /= e;
x = x1;
y = y1;
for (int i = 0; i < e; i++) {
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2i(int(x + 0.5), int(y + 0.5));
glEnd();
glFlush();
x += dx;
y += dy;
}
}
*/
void MidPointLine(int x0, int y0, int x1, int y1)
{
int a, b, d1, d2, d, x, y;
a = y0 - y1;
b = x1 - x0;
d = 2 * a + b;
d1 = 2 * a;
d2 = 2 * (a + b);
x = x0;
y = y0;
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
while (x < x1)
{
if (d < 0)
{
x++;
y++;
d += d2;
}
else
{
x++;
d += d1;
}
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
glFlush();
}
}
void display(void) {
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, 500, 500);
//DDA_Line(0, 500, 500, 0);
MidPointLine(100, 100, 300, 300);
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RED);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("DDA_line");
glutDisplayFunc(display);
glColor3f(1.0, 0.0, 1.0);//颜色
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glutMainLoop();
return 0;
}