B样条的C++实现

#pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )//去除控制台窗口
#include <iostream>
#include <gl/GLUT.h>
#include <map>
#include <vector>
#include<cmath>
#include <list>
#include <algorithm>
using namespace std;

struct Point {
	float x, y;
	Point(float _x, float _y) :x(_x), y(_y) {}
	Point() {}
	void operator =(Point& r) {
		x = r.x; y = r.y;
	}
	Point operator+(Point p){
		return Point(this->x + p.x, this-> y + p.y);
	}
};

Point P[1000];
float T[1000];
vector<Point> v;
int k=3;
int choice_id = -1;
int window_size = 800;
float XL=200, XR=600, YB=200, YT=600;
void initT(int n);

float cal(float a, float b);
void control_polygon();
void draw_rp(float x, float y);
void OnMouse(int button, int state, int x, int y);
void InitEnvironment();
void myMotion(int x, int y);
void deBoor();

int main(int argc, char* argv[]) {

	k= atoi(argv[1]);

	glutInit(&argc, argv);   //初始化GLUT
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(300, 100);
	glutInitWindowSize(window_size, window_size);
	glutCreateWindow("B样条");
	InitEnvironment();   //初始化
	glutMotionFunc(&myMotion);   //回调函数
	glutMouseFunc(&OnMouse);  //注册鼠标事件
	glutMainLoop();    //持续显示,当窗口改变会重新绘制图形

	return 0;
}

void InitEnvironment() {
	glClearColor(0.0, 0.0, 0.0, 1);
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glPointSize(6);
	glLineWidth(3);
	gluOrtho2D(0, window_size, 0, window_size);
	
}

void myMotion(int x, int y) {
	if (choice_id != -1) {
		v[choice_id].x = float(x);
		v[choice_id].y = float(y);
		deBoor();
	}
}

void draw_rp(float x, float y) {
	glBegin(GL_POINTS);
	glColor3f(1, 0, 0);
	glVertex2f(x, window_size - y);
	glEnd();
	glFlush();
}
void OnMouse(int button, int state, int x, int y)
//OnMouse坐标系x从左向右,y从上到下
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
		choice_id = -1;
		int t = v.size();
		draw_rp(x, y);
		for (int i = 0; i < t; i++) {
			if (abs(x - v[i].x) < 8 && abs(y - v[i].y) < 8) {//选中一个点
				choice_id = i; return;
			}
		}
		v.push_back(Point(x, y));
		if(t>=2)deBoor();
		else control_polygon();

	}
	else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN )
	{   //点击右键,选择顶点删除
		int t = v.size();
		for (int i = 0; i < t; i++) {
			if (abs(x - v[i].x) < 8 && abs(y - v[i].y) < 8) {//选中一个点
				for(int j = i; j < v.size()-1; j++)v[j] = v[j + 1];
				v.pop_back();
				deBoor();
				break;
			}
		}
		
	}
}

void deBoor() {
	glClear(GL_COLOR_BUFFER_BIT);
	vector<Point>res;
	int n = v.size() - 1;
	initT(n);//初始化节点矢量

	for (int j = k - 1; j <= n; j++)
	{//j为区间的末端点
		for (float t = T[j]; t < T[j + 1]; t+=0.01/n)
		{//在当前选定的区间[tj,tj+1)内
			for (int r = 1; r <= k - 1; r++)
			{//递推k-1层
				for (int i =j ; i >= j - k + r + 1; i--)
				{
					float part1 = cal(t - T[i], T[i + k - r] - T[i]);
					float part2 = cal(T[i + k - r] - t, T[i + k - r] - T[i]);
					if (r==1) {//第一轮输入控制点
						P[i].x = v[i].x * part1 + v[i - 1].x * part2;
						P[i].y = v[i].y * part1 + v[i - 1].y * part2;
					}
					else {//之后递推
						P[i].x = P[i].x * part1 + P[i - 1].x * part2;
						P[i].y = P[i].y * part1 + P[i - 1].y * part2;
					}
				}
			}
			res.push_back(P[j]);
		}
	}

	glBegin(GL_LINES);//多次调用画图的话,容易闪烁,这里开头调用一遍就够了
	glColor3f(0, 1, 0);
	int rest = res.size() - 2;
	for (int i = 0; i <= rest; i++) {
		glVertex2f(res[i].x, window_size - res[i].y);
		glVertex2f(res[i + 1].x, window_size - res[i + 1].y);
	}
	glEnd();
	glFlush();

	control_polygon();
}

void control_polygon() {
	int n = v.size() - 1;

	glBegin(GL_LINES);
	for (int i = 0; i <= n - 1; i++) {
		glColor3f(0, 0, 1);
		glVertex2f(v[i].x, window_size - v[i].y);
		glVertex2f(v[i + 1].x, window_size - v[i + 1].y);
	}
	glEnd();
	glFlush();
	for (int i = 0; i <= n; i++) {//点和线不能交叉使用
		draw_rp(v[i].x, v[i].y);
	}
}

void initT(int n) {
	int iv = n + 1 - k + 1;
	//均匀B样条
	/*for (int i = 0; i <= v.size() + k; i++)
		T[i] = i + 1;*/
		//准均匀B样条
	T[0] = 0;
	T[n + k] = 1;
	for (int i = 0; i <= k - 1; i++)T[i] = 0;
	for (int i = k; i <= n; i++)T[i] = T[i - 1] + 1.0 / iv;
	for (int i = n + 1; i <= n + k; i++)T[i] = 1;
}

float cal(float a, float b) {
	if (a == 0.0 && b == 0.0)return 0;
	else return a / b;
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值