文章目录
- 其他计算机图形学实验
- 前言
- 1.辅助画椭圆算法
- 2.椭圆的中点算法(两种)
- 3.改变鼠标动作响应函数
- 4. 完整代码
- 5. 总结
其他计算机图形学实验
传送门
前言
实现绘制椭圆的中点算法,并和鼠标进行交互。
具体原理略过,会贴上完整代码,可直接运行。
环境:
vs2019,OpenGL的库(可以搜索如何用vs使用OpenGL的库,可以使用vs自带的插件或者其他方法,很方便)
要点:
1.设计画椭圆的算法。设置椭圆中心和长短半轴的全局变量,通过鼠标得到全局变量的值,再传入函数,进行椭圆的绘制。
2.改变鼠标点击和鼠标拖拽的响应事件。
最终效果:
用鼠标在界面上拖拽,就会生成一个椭圆
1.辅助画椭圆算法
由于椭圆的对称性,我们只用画出其四分之一即可。
//辅助画椭圆算法
void OvalPoints(int x, int y, int x0, int y0)
{
glVertex2i(x + x0, y + y0);
glVertex2i(-x + x0, y + y0);
glVertex2i(x + x0, -y + y0);
glVertex2i(-x + x0, -y + y0);
}
2.椭圆的中点算法(两种)
方法一
/*椭圆的中点算法*/
void MidpointOval(int x0, int y0, int a, int b)
{
glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
glBegin(GL_POINTS);
int x = 0, y = b;
int a2 = a * a, b2 = b * b;
float d1 = b2 + a2 * (0.25 - b);
float d2 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2;
OvalPoints(x, y, x0, y0);
int flag = 0; //分成上下部分的标志
while (y>=0) {
glBegin(GL_POINTS);
OvalPoints(x, y, x0, y0);
if (flag == 0) {
if (a2*y<b2*x) flag = 1;
}
if (flag == 0) { //上半部分
x++;
if (d1 < 0) {
d1 += b2 * (2 * x + 3);
}
else {
y--;
d1 += b2 * (2 * x + 3) + a2 * (2 - 2 * y);
}
}
else { //下半部分
y--;
if (d2 >= 0) { //取正下方的点
d2 += a2 * (3 - 2 * y);
}
else {
x++;
d2 += b2 * (2 * x + 2) + a2 * (3 - 2 * y);
}
}
}
glEnd();
glFlush();
}
方法二
/*椭圆的中点算法*/
void MidpointOval(int x0, int y0, int a, int b)
{
glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
glBegin(GL_POINTS);
int x = 0, y = b;
int a2 = a * a, b2 = b * b;
float d1 = b2 + a2 * (0.25 - b);
float d2 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2;
//float d2 = sqrt(b * (x + 0.5) + a * (y - 1)) - a * b;
//glVertex2i(x0, y0);
OvalPoints(x, y, x0, y0);
while (a2*y>b2*x) { //注意这个判断!!!
glBegin(GL_POINTS);
OvalPoints(x, y, x0, y0);
x++;
//++x;
if (d1 < 0) {
d1 += b2 * (2 * x + 3);
}
else {
y--;
//--y;
d1 += b2 * (2 * x + 3) + a2 * (2 - 2 * y);
}
}
x--; y++;
while (y > 0) {
y--;
if (d2 >= 0) { //取正下方的点
d2 += a2 * (3 - 2 * y);
}
else {
x++;
d2 += b2 * (2 * x + 2) + a2 * (3 - 2 * y);
}
glBegin(GL_POINTS);
OvalPoints(x, y, x0, y0);
}
glEnd();
glFlush();
}
3.改变鼠标动作响应函数
//鼠标拖动
void dragmouse(int x, int y) {
m1 = x;
n1 = y;
mm = (m0 + m1) / 2;
nn = (n0 + n1) / 2;
a = abs(m1 - m0) / 2;
b = abs(n1 - n0) / 2;
DrawOval(); //画线
glFlush();
}
//鼠标监听,画点
void mymouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
m1 = x;
n1 = y;
mm = (m0 + m1) / 2;
nn = (n0 + n1) / 2;
a = abs(m1 - m0) / 2;
b = abs(n1 - n0) / 2;
printf("椭圆起始点坐标为:(%d,%d),长半轴为:%d,短半轴为:%d\n", m0, n0, a, b);
DrawOval();
glFlush();
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { //按下鼠标,是起点
m0 = x;
n0 = y;
}
}
4. 完整代码
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<gl\glut.h>
using namespace std;
int m0, n0, m1, n1;//声明全局变量
int mm, nn; //椭圆的中心点
int a, b; //椭圆的长半轴和短半轴
int winwidth = 800, winheight = 500;//窗口长宽
void DrawOval(); //实际上画圆的函数
void MidpointOval(int, int, int, int); //椭圆的中点算法
//实际上画圆的函数
void DrawOval() {
MidpointOval(mm, nn, a, b); //椭圆的中点算法
}
//辅助画椭圆算法
void OvalPoints(int x, int y, int x0, int y0)
{
glVertex2i(x + x0, y + y0);
glVertex2i(-x + x0, y + y0);
glVertex2i(x + x0, -y + y0);
glVertex2i(-x + x0, -y + y0);
}
/*椭圆的中点算法*/
void MidpointOval(int x0, int y0, int a, int b)
{
glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
glBegin(GL_POINTS);
int x = 0, y = b;
int a2 = a * a, b2 = b * b;
float d1 = b2 + a2 * (0.25 - b);
float d2 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2;
OvalPoints(x, y, x0, y0);
/*方法一*/
while (a2*y>b2*x) { //注意!!!
glBegin(GL_POINTS);
OvalPoints(x, y, x0, y0);
x++;
//++x;
if (d1 < 0) {
d1 += b2 * (2 * x + 3);
}
else {
y--;
//--y;
d1 += b2 * (2 * x + 3) + a2 * (2 - 2 * y);
}
}
x--; y++;
while (y > 0) {
y--;
if (d2 >= 0) { //取正下方的点
d2 += a2 * (3 - 2 * y);
}
else {
x++;
d2 += b2 * (2 * x + 2) + a2 * (3 - 2 * y);
}
glBegin(GL_POINTS);
OvalPoints(x, y, x0, y0);
}
/*方法二*/
//int flag = 0; //分成上下部分的标志
//while (y>=0) {
// glBegin(GL_POINTS);
// OvalPoints(x, y, x0, y0);
// if (flag == 0) {
// if (a2*y<b2*x) flag = 1;
// }
// if (flag == 0) { //上半部分
// x++;
// if (d1 < 0) {
// d1 += b2 * (2 * x + 3);
// }
// else {
// y--;
// d1 += b2 * (2 * x + 3) + a2 * (2 - 2 * y);
// }
// }
// else { //下半部分
// y--;
// if (d2 >= 0) { //取正下方的点
// d2 += a2 * (3 - 2 * y);
// }
// else {
// x++;
// d2 += b2 * (2 * x + 2) + a2 * (3 - 2 * y);
// }
// }
//}
glEnd();
glFlush();
}
//鼠标拖动
void dragmouse(int x, int y) {
m1 = x;
n1 = y;
mm = (m0 + m1) / 2;
nn = (n0 + n1) / 2;
a = abs(m1 - m0) / 2;
b = abs(n1 - n0) / 2;
DrawOval(); //画线
glFlush();
}
//鼠标监听,画点
void mymouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
m1 = x;
n1 = y;
mm = (m0 + m1) / 2;
nn = (n0 + n1) / 2;
a = abs(m1 - m0) / 2;
b = abs(n1 - n0) / 2;
printf("椭圆起始点坐标为:(%d,%d),长半轴为:%d,短半轴为:%d\n", m0, n0, a, b);
DrawOval();
glFlush();
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { //按下鼠标,是起点
m0 = x;
n0 = y;
}
}
void init() {
glClearColor(1, 1, 1, 1);//设置绘制窗口颜色为白色
glClear(GL_COLOR_BUFFER_BIT);//清除窗口内容
glPointSize(3.0f);//设置点的大小
/*设置为投影类型模式和其他观察参数*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, winwidth, winheight, 0);
glColor3f(0, 1, 1);//设置画点的颜色
}
int main(int argc, char** argv) {
glutInit(&argc, argv);//初始化
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置绘制模式
glutInitWindowPosition(350, 200);//设置窗口出现的位置
glutInitWindowSize(winwidth, winheight);//设置窗口大小
glutCreateWindow("画椭圆");//创建窗口
init();
glutDisplayFunc(DrawOval);//绘制回调函数,glut机制,它觉得需要重新绘制的时候就会执行
glutMouseFunc(mymouse);//鼠标监听回调函数
glutMotionFunc(dragmouse);//鼠标拖动
glutMainLoop();
}
5. 总结
椭圆是在圆的基础上进行改变,算法更难了一点。要注意椭圆从上半部分变到下半部分的判断点。因为这个判断点弄错了,找了好久的bug都没找出来