实 验 报 告
一、实验目的
- 了解光栅化图形学的主要理论和知识。
- 了解OpenGL图形库的构成,会设计OpenGL的程序。
- 掌握基本图形的生成原理,学会设计基本图形的生成算法。包括画线算法、画圆算法和多边形填充算法的原理和实现方法。
- 设计中点画线算法,对给定的任意起点和终点的线段,采用中点画线算法设计画线程序,并能保证程序的正确性。
- 掌握多边形填充算法的基本原理和方法,掌握有序边表法和扫描线种子填充算法的原理。根据给定的类设计实现有序边表法填充多边形的程序。
二、实验内容与实验步骤
中点画线算法:
- 完成中点画线算法的设计,调用OpenGL的画点的函数,采用中点画线算法完成二维线段的绘制算法。
- 补全了lineBres函数以及pointFun函数。
- lineBres函数:一共有四个参数,表示起始点和终止点的坐标信息。分四种情况实现中点画线算法,分别是:0<=m<=1,m>=1,-1<=m<=0以及m<=-1。在函数中调用glVertex2d(x,y)函数,对每个坐标点(x,y)进行绘制。
- pointFun函数:利用glColor3f(GLfloat,GLfloat,GLfloat)函数设置画线颜色,之后调用lineBres函数绘制每条线。
- 实现后调用OpenGL的画线函数画线对比自己的实验结果。
DDA画线算法:
- 完成DDA画线算法的设计,调用OpenGL的画点的函数,采用DDA画线算法完成二维线段的绘制算法。
- 调用文件里所给的lineDDA函数,并创建与pointFun函数具有相同功能的DDALine函数。
- lineDDA函数:一共有四个参数,表示起始点和终止点的坐标信息。
- DDALine函数:利用glColor3f(GLfloat,GLfloat)函数设置画线颜色,之后调用lineDDA函数绘制每条线。
多边形填充算法:
- 根据给定的类设计实现有序边表法填充多边形的程序。
- 创建drawFrame()函数,用以勾画填充图形的外轮廓。
- 导入参考文件里的myclass.h以及myclass.cpp文件,调用其中的类以及函数,在main.cpp文件内创建新函数scanFill()函数,实现多边形填充。
- 在main()函数内调用drawFrame()函数以及scanFill()函数,实现描边以及填充。
三、实验环境
- 操作系统:macOS Big Sur Version 11.6
- 调试软件:Xcode Version 13.0
- 上机地点:xxx
- 机器台号:xxx
四、实验过程与分析
中点画线算法:
lineBres函数:
流程图
修改:Build Settings --> Linking --> Other Linker Flags 添加 “-framework OpenGL”
- 定义函数出错
修改:将函数改名为ro(猜测round和其他功能重名)
坐标信息
原点位置:视口中央
X正方向:视口内右方向
Y正方向:视口内上方向
视口大小:600*600
DDA画线算法:
lineDDA函数:
流程图
最开始文件中给的循环代码为:while (x <= x2),运行结果:
缺少斜率为负的情况。
修改:将循环判定部分修改为for (int i=1; i<=epsl; i++),即可绘制出正确图案。
坐标信息
坐标原点位置:视口中央
X正方向:视口内右方向
Y正方向:视口内上方向
视口大小:600*600
多边形填充算法:
scanFill函数:
流程图
调试中的问题
- 问题:输入的数据类型和定义不符
修改:将point均改为引用类型。
- 问题:指针应采用->样式调用
修改:把head.GetNextedge改为head->GetNextedge
- 问题:运行函数后没有图形。
修改:在myDisplay()函数末尾添加glFlush()函数调用。
坐标信息
坐标原点位置:视口中央
X正方向:视口内右方向
Y正方向:视口内上方向
视口大小:600*600
五、实验结果总结
中点画线算法:
DDA画线算法:
多边形填充算法:
代码:
// 画线算法
#define GL_SILENCE_DEPRECATION
#include<iostream>
#include<GLUT/glut.h> //windows改成<GL/glut.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
using namespace std;
void init(void)
{
glClearColor(1.0,1.0,0.0); // Set display-window color to white.
glMatrixMode(GL_PROJECTION); // Set projection parameters.
glPointSize(2.0f);
gluOrtho2D(-200,200,-200,200);
GLfloat sizes[2];
GLfloat step;
glGetFloatv(1.0f,sizes);
glGetFloatv(1.0f,& step);
}
int ro(const float a)
{
int b = int(a+0.5);
return b;
}
void lineDDA(int x1,int y1,int x2,int y2);
void lineBres(int x1,int y2);
void myReshape(GLsizei w,GLsizei h) {
glViewport(0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w/2,w/2,-h/2,h/2,-10,10);
}
void myDisplay() {
glClearColor(0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,1.0);
//glRectf(100,100,20,20);
lineDDA(10,10,150);
lineBres(10,30,170);
glFlush();
}
void lineDDA(int x1,int y2) {
float dx,dy;
int epsl;
float xIncre,yIncre;
dx = x2 - x1;
dy = y2 - y1;
float x = x1;
float y = y1;
if (abs(dx) > abs(dy))
epsl = abs(dx);
else
epsl = abs(dy);
xIncre = (float)dx / epsl;
yIncre = (float)dy / epsl;
glBegin(GL_POINTS);
for (int i=1; i<=epsl; i++)
{
glVertex2i(int(x + 0.5),int(y + 0.5));
x += xIncre;
y += yIncre;
}
}
void lineBres(int x1,int y2)
{
int x = x1;
int y = y1;
if (x1 > x2)
{
x = x1; x1 = x2; x2 = x; x = x1;
y = y1; y1 = y2; y2 = y; y = y1;
}
glBegin(GL_POINTS);
int a = y1 - y2;
int b = x2 - x1;
float k = 0;
int d;
if (x1 != x2)
{
k = -1.0 * a / b;
}
else
{
if (y2 >= 0)
{
while (y < y2)
{
glVertex2i(x,y);
y++;
}
}
else
{
while (y > y2)
{
glVertex2i(x,y);
y--;
}
}
}
if (k >= 0.0 && k < 1.0)
{
d = 2 * a + b;
while (x <= x2)
{
glVertex2i(x,y);
if (d >= 0)
{
d += 2 * a;
x++;
}
else {
d += 2 * a + 2 * b;
x++;
y++;
}
}
}
else if (k >= 1.0)
{
d = 2 * b + a;
while (y <= y2)
{
glVertex2i(x,y);
if (d >= 0)
{
d += 2 * b + 2 * a;
x++;
y++;
}
else {
d += 2 * b;
y++;
}
}
}
else if (k > -1.0 && k <= 0.0)
{
d = 2 * a - b;
while (x <= x2)
{
glVertex2i(x,y);
if (d >= 0)
{
d += 2 * a - 2 * b;
x++;
y--;
}
else {
d += 2 * a;
x++;
}
}
}
else
{
d = a - 2 * b;
while (y >= y2)
{
glVertex2i(x,y);
if (d >= 0)
{
d += -2 * b;
y--;
}
else {
d += 2 * a - 2 * b;
x++;
y--;
}
}
}
glEnd();
}
void pointFun(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
glColor3f(1.0,0.0);//红
lineBres(1,1,50);//(1,1) (100,50)
glColor3f(1.0,0.5,0.0);//橙
lineBres(1,50,100);//(1,1) (50,100)
glColor3f(1.0,0.0);//黄
lineBres(-1,-100,50);//(-1,1) (-100,50)
glColor3f(0.0,0.0);//绿
lineBres(-1,-50,100);//(-1,1) (-50,100)
glColor3f(0.0,1.0);//青
lineBres(-1,-1,-50);//(-1,-1) (-100,-50)
glColor3f(0.0,1.0);//蓝
lineBres(-1,-100);//(-1,-1) (-50,-100)
glColor3f(1.0,1.0);//紫
lineBres(1,-50);//(1,-1) (100,-50)
glColor3f(0.0,0.0);//黑
lineBres(1,-100);//(1,-1) (50,-100)
glColor3f(0.0,0.0);//黑
lineBres(0,0);//(0,0) (100,0)
glColor3f(0.0,100);//(0,0) (0,100)
glEnd();
glFlush();
}
void DDALine(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS);
glColor3f(1.0,0.0);//红
lineDDA(1,0.0);//橙
lineDDA(1,0.0);//黄
lineDDA(-1,0.0);//绿
lineDDA(-1,1.0);//青
lineDDA(-1,1.0);//蓝
lineDDA(-1,1.0);//紫
lineDDA(1,0.0);//黑
lineDDA(1,0.0);//黑
lineDDA(0,100)
glEnd();
glFlush();
}
void sysLine(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
glColor3f(1.0,0.0);//红
glVertex2f(1,1);
glVertex2f(100,50);
glColor3f(1.0,0.0);//橙
glVertex2f(1,1);
glVertex2f(50,100);
glColor3f(1.0,0.0);//黄
glVertex2f(-1,1);
glVertex2f(-100,50);
glColor3f(0.0,0.0);//绿
glVertex2f(-1,1);
glVertex2f(-50,100);
glColor3f(0.0,1.0);//青
glVertex2f(-1,-1);
glVertex2f(-100,-50);
glColor3f(0.0,1.0);//蓝
glVertex2f(-1,-1);
glVertex2f(-50,-100);
glColor3f(1.0,1.0);//紫
glVertex2f(1,-1);
glVertex2f(100,0.0);//黑
glVertex2f(1,-1);
glVertex2f(50,-100);
glVertex2f(0,0);
glVertex2f(100,0);
glVertex2f(0,100);
glEnd();
glFlush();
}
int main(int argc,char** argv)
{
glutInit(&argc,argv); // Initialize GLUT.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // Set display mode.
glutInitWindowPosition(50,100); // Set top-left display-window position.
glutInitWindowSize(600,600); // Set display-window width and height.
glutCreateWindow("DDA画线算法"); // Create display window.
init(); // Execute initialization procedure.
glutDisplayFunc(DDALine); // Send graphics to display window.
glutMainLoop();// Send graphics to display window. // Display everything and wait.
return 0;
}
// 多边形填充算法
#define GL_SILENCE_DEPRECATION
#include <iostream>
using namespace std;
#include <GLUT/glut.h> // windows改成<GL/glut.h>
#include "myclass.h"
void drawFrame();
void scanFill();
void myReshape(GLsizei w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w / 2,w / 2,-h / 2,h / 2,10);
}
void myDisplay() {
glClearColor(1.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0,0.0);
//glRectf(100,20);
drawFrame();
scanFill();
glFlush();
}
int main(int argc,char* argv[]) {
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(600,600);
glutCreateWindow("多边形填充");
glutDisplayFunc(myDisplay);
glutReshapeFunc(myReshape);
glutMainLoop();
return 0;
}
void drawFrame(){
Point2D point_1(0,0);
Point2D point_2(-100,100);
Point2D point_3(100,100);
Point2D point_4(0,200);
glBegin(GL_LINE_LOOP);
glVertex2i(point_1.GetX(),point_1.GetY());
glVertex2i(point_2.GetX(),point_2.GetY());
glVertex2i(point_3.GetX(),point_3.GetY());
glVertex2i(point_4.GetX(),point_4.GetY());
glEnd();
}
void scanFill(){
NewEdgeTable NET;
ActiveEdgeTable AET;
ActiveEdge point1(0,100);
NET.InsertNewEdge(&point1,0);
ActiveEdge point2(0,100);
point1.SetNext(&point2);
ActiveEdge point3(-100,200);
NET.InsertNewEdge(&point3,100);
ActiveEdge point4(100,200);
point3.SetNext(&point4);
int i=0;
//遍历新边表
for (ActiveEdge* point : NET.rowTable){
ActiveEdge * ptr = AET.head->GetNextedge();
//遍历活性边表 删去非必要的边
while (ptr != NULL) {
if (ptr->GetMax()==i){
ActiveEdge* ptr2 = ptr;
ptr = ptr->GetNextedge();
AET.DeleteActiveEdge(ptr2);
}else{
float x = ptr->GetCurrentX()+ptr->GetDX();
ptr->SetCurrentX(x);
ptr = ptr->GetNextedge();
}
}
//放入活性边表
while (point != NULL) {
ActiveEdge* point2 = point;
point = point->GetNextedge();
AET.InsertActiveEdge(point2);
}
AET.sort();
ptr = AET.head->GetNextedge();
glBegin(GL_LINES);
glColor3f(0.0,0.0);
//遍历新的活性边表 填充
while (ptr!=NULL){
int x = ptr->GetCurrentX();
glVertex2i(x,i);
ptr = ptr->GetNextedge();
x = ptr->GetCurrentX();
glVertex2i(x,i);
ptr = ptr->GetNextedge();
}
glEnd();
i++;
}
}
六、附录
- 设想:可以考虑用每一步都定格一小段时间看真实的扫描过程,但因能力不足未实现。
- 资料:
-
思考题:
- Q:对比DDA画线算法,Bresenham中点画线算法有哪些优点?A:D DA算法中的y和k都必须用浮点数表示,并且每一步运算都要对y进行舍入取整,这不利于硬件实现。中点画线法只包含整数变量,并且不含乘除法,速度更快效率更高。
- Q:举例说明种子填充算法适合什么应用场景? A:如果要填充的区域是以图像元数据方式给出的,通常使用种子填充算法进行区域填充。种子填充算法需要给出图像数据的区域,以及区域内的一个点,这种算法比较适合人机交互方式进行的图像填充操作,不适合计算机自动处理和判断填色。
// 大家随便看看,当初做实验真的是被整麻了……心态一整个没有hhh。
// 要是有错误欢迎指出,用到了麻烦点个赞点个关注~(没兴趣真的不要学数媒 原文地址:https://blog.csdn.net/Kqp12_27 版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。