#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;
}
B样条的C++实现
最新推荐文章于 2024-07-10 14:37:17 发布