opengl+glfw+glew绘制曲线

使用求值器让若干点均匀分布,形成曲线

#include <iostream>
#include <Windows.h>

// GLEW    
#include <GL/glew.h>    

// GLFW 
#include <GLFW/glfw3.h>   

GLuint WIDTH = 400, HEIGHT = 400;
GLfloat gX = 0, gY = 0;
int choosedPoint = -1;
GLfloat pointWidth = 9.0f;

#define POINTS_CNT         6
#define VALUE_PER_POINT    3
static GLfloat controlPoints[POINTS_CNT][VALUE_PER_POINT] = {}, originPoints[POINTS_CNT][VALUE_PER_POINT] = {
	{-0.8f, 0.8f, 0.0f},
	{-0.8f, 0.0f, 0.0f},
	{0.0f, -0.0f, 0.0f},
	{0.0f, -0.0f, 0.0f},
	{0.8f, -0.0f, 0.0f},
	{0.8f, -0.8f, 0.0f}
};

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void mouseButton_callback(GLFWwindow* window, int button, int action, int mode);
void mouseMove_callback(GLFWwindow* window, double xPos, double yPos);
void windowResize_callback(GLFWwindow* window, int width, int height);

void resetControlPoints()
{
	for (int i = 0; i < POINTS_CNT; ++i)
	{
		for (int j = 0; j < VALUE_PER_POINT; ++j)
		{
			controlPoints[i][j] = originPoints[i][j];
		}
	}

}

//opengl在glfw中显示规则:
//1.画布中间坐标为0,0。长宽个1.0f个单位,超过1.0f的部分不会被绘制出来
void DrawLine()
{
	glColor4b(99, 38, 13, 90);

	glBegin(GL_LINES);

	glVertex2f(-1 + gX * 4, 1 + gY * 4);//指定第一个点
	glVertex2f(-0.8 + gX * 4, gY * 4 + 0.8);//指定第二个点

	glEnd();//结束
}

void DrawBezier()
{
	glColor3b(99, 38, 13);
    //第三个参数最好是1.0f,
	glMap1f(GL_MAP1_VERTEX_3, 0.0f, 0.8f, VALUE_PER_POINT, POINTS_CNT, &controlPoints[0][0]);
	glEnable(GL_MAP1_VERTEX_3);

	glBegin(GL_LINE_STRIP);

	//glEvalCoord1f,从u1取值到u2,线性均匀排列,取多少次就是分多少段,如果段数少,可能会有明显的曲折,最好是0-1.0f
	for (GLfloat i = 0; i <= 0.8; i += 0.02)
	{
		glColor3f(i, 1 - i, 0.4f + i);
		glEvalCoord1f(i);
	}

	glEnd();

	glColor3b(0, 0, 0);
	glPointSize(pointWidth);
	glBegin(GL_POINTS);
	for (int i = 0; i < POINTS_CNT; ++i)
	{
		glVertex3fv(controlPoints[i]);
	}
	glEnd();
}

void render(GLFWwindow* window)
{
	glClearColor(1.0f, 0.8f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);

	DrawLine();
	DrawBezier();
}

void initWindow(GLFWwindow* window)
{
	glfwMakeContextCurrent(window);

	//设置按键回调
	glfwSetKeyCallback(window, key_callback);
	//设置鼠标按键点下松开的回调
	glfwSetMouseButtonCallback(window, mouseButton_callback);
	//设置鼠标移动的回调
	glfwSetCursorPosCallback(window, mouseMove_callback);

	//设置窗口大小改变的回调,让绘画区域在窗口中间
	glfwSetWindowSizeCallback(window, windowResize_callback);
}

void initParam()
{
	//显示规则:窗口左下角坐标为0,0;所以下行代码表示在窗口左下角向右向上的400个像素单位作为画布
	glViewport(0, 0, WIDTH, HEIGHT);//设置显示区域400*400,但是可以拖动改变窗口大小
	glLineWidth(3.0);//设置线条宽度,3个像素

	glEnable(GL_BLEND);

	glEnable(GL_POINT_SMOOTH);
	glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);//设置点圆滑

	glEnable(GL_LINE_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);//设置线光滑

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

}

int main()
{
	glfwInit();

	GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}

	initWindow(window);

	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to initialize GLEW" << std::endl;
		return -1;
	}

	initParam();
	resetControlPoints();

	// Game loop    
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();

		render(window);

		glfwSwapBuffers(window);
	}

	// Terminate GLFW, clearing any resources allocated by GLFW.    
	glfwTerminate();
	return 0;
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)//按下esc退出程序
	{
		glfwSetWindowShouldClose(window, GL_TRUE);
	}
	else if (key == GLFW_KEY_LEFT)
	{
		gX -= 0.01;
	}
	else if (key == GLFW_KEY_RIGHT)
	{
		gX += 0.01;
	}
	else if (key == GLFW_KEY_UP)
	{
		gY += 0.01;
	}
	else if (key == GLFW_KEY_DOWN)
	{
		gY -= 0.01;
	}
}

//窗口坐标转视图坐标
void windowPos2CoordiatePos(GLFWwindow* window, double xPos, double yPos, double *pX, double *pY)
{
	int width, height;
	glfwGetWindowSize(window, &width, &height);

	xPos -= (width - WIDTH) / 2;
	*pX = xPos / (WIDTH / 2) - 1;

	yPos -= (height - HEIGHT) / 2;
	*pY = 1 - yPos / (HEIGHT / 2);
}

//x,y视图坐标系坐标转xpos、ypos窗口坐标
void coordiatePos2WindowPos(GLFWwindow* window, double x, double y, double *pXPos, double *pYPos)
{
	int width, height;
	glfwGetWindowSize(window, &width, &height);

	*pXPos = (x + 1) * (WIDTH / 2);
	*pYPos = (1 - y) * (WIDTH / 2);

	*pXPos += (width - WIDTH) / 2;
	*pYPos += (height - HEIGHT) / 2;
}

//判断一个窗口坐标是否在视图坐标系的某个点中,
bool posInPoint(GLFWwindow* window, double xPos, double yPos, double x, double y, double pointWidth)
{
	double trueXPos, trueYPos;
	coordiatePos2WindowPos(window, x, y, &trueXPos, &trueYPos);

	if (xPos >= trueXPos - pointWidth
		&& xPos <= trueXPos + pointWidth
		&& yPos >= trueYPos - pointWidth
		&& yPos <= trueYPos + pointWidth)
	{
		return true;
	}

	return false;
}

void mouseButton_callback(GLFWwindow* window, int button, int action, int mode)
{
	double xPos = 0, yPos = 0;
	double x = 0, y = 0;
	glfwGetCursorPos(window, &xPos, &yPos);

	WCHAR str[200];
	swprintf(str, 400, L"button %d, action %d, mode %x [%lf,%lf]\r\n", button, action, mode, xPos, yPos);
	//OutputDebugString(str);

	choosedPoint = -1;

	windowPos2CoordiatePos(window, xPos, yPos, &x, &y);

	for (int i = 0; i < POINTS_CNT && (GLFW_PRESS == action); ++i)
	{
		if (posInPoint(window, xPos, yPos, controlPoints[i][0], controlPoints[i][1], pointWidth))
		{
			choosedPoint = i;
			break;
		}
	}

	if (GLFW_PRESS == action && (GLFW_MOD_CONTROL & mode))
	{
		resetControlPoints();
	}
}

void mouseMove_callback(GLFWwindow* window, double xPos, double yPos)
{
	if (choosedPoint >= 0 && choosedPoint <= POINTS_CNT - 1)
	{
		double newX = 0, newY = 0;
		windowPos2CoordiatePos(window, xPos, yPos, &newX, &newY);
		controlPoints[choosedPoint][0] = newX;
		controlPoints[choosedPoint][1] = newY;
	}
}

void windowResize_callback(GLFWwindow* window, int width, int height)
{
	WIDTH = HEIGHT = width > height ? height : width;
	//左下角是0, 0坐标, x,y说就是相对于左下角的像素距离
	glViewport((width - WIDTH) / 2, (height - HEIGHT) / 2, WIDTH, HEIGHT);
}

效果:

监控鼠标按下,如果在6个点里面,就允许拖动,

一共6个点,可以设置成3个、4个、5个,

监控键盘上下左右键,是直线线条上下左右移动

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++调用glew绘制全向天线水平波瓣图的代码示例: ```c++ #include <GL/glew.h> #include <GLFW/glfw3.h> #include <iostream> #include <cmath> // 定义窗口大小 const int WIDTH = 800; const int HEIGHT = 800; // 定义绘制圆的分辨率 const int RESOLUTION = 100; // 定义天线的辐射功率模型 double powerModel(double theta) { // 这里使用简单的cos(theta)的模型,实际中需要根据具体情况进行定义 return std::cos(theta); } // 绘制全向天线水平波瓣图 void drawAntenna() { glBegin(GL_LINE_STRIP); glColor3f(1.0f, 1.0f, 1.0f); for (int i = 0; i <= RESOLUTION; i++) { double theta = i * 2 * M_PI / RESOLUTION; double power = powerModel(theta); double x = power * std::cos(theta); double y = power * std::sin(theta); glVertex2d(x, y); } glEnd(); } // 窗口大小变化回调函数 void resizeCallback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); double aspectRatio = static_cast<double>(width) / static_cast<double>(height); if (width >= height) { glOrtho(-1.0 * aspectRatio, 1.0 * aspectRatio, -1.0, 1.0, -1.0, 1.0); } else { glOrtho(-1.0, 1.0, -1.0 / aspectRatio, 1.0 / aspectRatio, -1.0, 1.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } // 主函数 int main() { // 初始化GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return -1; } // 创建窗口 GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Antenna Pattern", nullptr, nullptr); if (!window) { std::cerr << "Failed to create window" << std::endl; glfwTerminate(); return -1; } // 设置窗口大小变化回调函数 glfwSetWindowSizeCallback(window, resizeCallback); // 设置当前上下文 glfwMakeContextCurrent(window); // 初始化GLEW if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW" << std::endl; glfwTerminate(); return -1; } // 设置视口 glViewport(0, 0, WIDTH, HEIGHT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // 渲染循环 while (!glfwWindowShouldClose(window)) { // 清空缓冲区 glClear(GL_COLOR_BUFFER_BIT); // 绘制天线 drawAntenna(); // 交换缓冲区 glfwSwapBuffers(window); // 处理事件 glfwPollEvents(); } // 清理并退出 glfwTerminate(); return 0; } ``` 这段代码使用OpenGL绘制全向天线水平波瓣图,使用了GLFWGLEW库来初始化窗口和OpenGL环境,并使用glOrtho函数设置了正交投影矩阵。在绘制天线时,使用了powerModel函数来计算在不同方向上的辐射功率,并使用glBegin和glEnd函数绘制出天线的形状。最后,使用glfwSwapBuffers函数交换缓冲区来显示绘制结果,并在渲染循环中不断更新窗口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值